6

名前付きの独自のクラスでUITextFieldDelegateを実装するデリゲート オブジェクトを作成しNumericTextFieldDelegate、この方法でコントローラーでデリゲートを初期化しました。

textFieldName.delegate = [NumericTextFieldDelegate new];

そして、私はコンパイラからこの警告を受けました:

Assigning retained object to unsafe property; object will be released after assignment

つまり、割り当て後にオブジェクトが解放され、実際にアプリケーションを実行してUITextFieldにフォーカスするEXC_BAD_ACCESSと、アプリがクラッシュします...

私が見つけたそれを機能させる唯一の方法は、のインスタンスをディスパッチするファクトリメソッドで静的変数を作成することですNumericTextFieldDelegate:

@interface NumericTextFieldDelegate : NSObject <UITextFieldDelegate>

+(NumericTextFieldDelegate *) getDelegate;

@end

@implementation NumericTextFieldDelegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string];

    // This allows backspace
    if ([resultingString length] == 0) {
        return true;
    }

    NSInteger holder;
    NSScanner *scan = [NSScanner scannerWithString: resultingString];

    return [scan scanInteger: &holder] && [scan isAtEnd];
}

+(NumericTextFieldDelegate *) getDelegate {
    static NumericTextFieldDelegate *del;
    @synchronized(del) {
        if(del == nil)
            del = [NumericTextFieldDelegate new];
    }
    return del;
}

@end

そして、この方法でデリゲートを割り当てると:

textFieldName.delegate = [NumericTextFieldDelegate getDelegate];

すべてうまくいきますが、私の質問は次のとおりです。

クラスの匿名の新しいインスタンスを単純に割り当てることができないのはなぜですか? 割り当て後にオブジェクトが自動的に解放されるのはなぜですか?

なぜこの回避策が必要なのですか?

ありがとう。

4

4 に答える 4

2

@Inaziger の分析に同意します。UITextField インスタンスのデリゲートは、一種の弱参照です。割り当てられたデリゲートは保持されません。ARCによると、デリゲートはnilになり、誰もそれへの参照を保持しません。したがって、デリゲートが呼び出されるように、それを保持するのは割り当て担当者次第です。以前の回避策をコーディングすると、次のようになります。

- (void) somemethod {
...
id<UITextFieldDelegate> tempDelegate = [NumericTextFieldDelegate new];
textFieldName.delegate = tempDelegate;
...
}

textFieldName のインスタンスは、何らかの方法でローカルに作成されたデリゲートへの参照を取得しました。メソッド呼び出しの後、ARC は temDelegate を nil に設定します。ただし、テキスト フィールドのデリゲートは、後で ARC によって解放される、割り当てられたメモリへのポインターを引き続き保持します。これが、不正なメモリ アクセス クラッシュが発生した理由です。

クラスで del を static var として保持することにより、nil に設定しない限り、アプリの実行サイクル中に保持されます。static del はクラスレベルのメンバとして残しておき、忘れずに解放できるようにセッターを用意したほうがいいと思います。何かのようなもの:

// in interface definition
+(NumericTextFieldDelegate *) getDelegate;
+(void) setDelegate:(id)newDel;

// in implementation
static NumericTextFieldDelegate* del;

+(NumericTextFieldDelegate *) getDelegate {
  @synchronized(del) {
    if(del == nil)
      del = [NumericTextFieldDelegate new];
    }
  return del;
}

+(void) setDelegate:(id)newDel {
   del = newDel;
}

ちなみに、以前の回避策コードをそのまま保持することもできます。デリゲートをテキスト フィールドのクラスにクラス メンバー変数またはプロパティとして保持できます。

@interface myTextFieldContainer () {
@proerpty (strong) id<UITextFieldDelegate> delHolder;
...
}

@implementaion myTextFieldContainer {
@sythysis delHolder = _delHodler;
...
self.delHolder = [NumericTextFieldDelegate new];
textFieldName.delegate = self.delHolder;

上記の戦略の利点は、View Controller がなくなったときにデリゲートを解放することを心配しないことです。

于 2012-06-01T01:54:14.960 に答える
1

クラスの匿名の新しいインスタンスを単純に割り当てることができないのはなぜですか? 割り当て後にオブジェクトが自動的に解放されるのはなぜですか?

なぜこの回避策が必要なのですか?

クラスの新しいインスタンスを割り当てることができます。ただし、強い参照がないため、すぐに解放されます。前述のように、保持サイクルを防ぐための textfield.delegate による弱い参照 (安全でない保持されていない) のみです。そして、それはまさに警告があなたに伝えていることです. ただし、このシングルトンのようなパターンは使用しません。デリゲート オブジェクトに強力なプロパティを追加し、そのプロパティ値をテキスト フィールドのデリゲートとして割り当てるだけです。

@property (nonatomic,strong) MyDelegateObject delegateObject;

Self.delegateObject = [MyDelegateObject new];
Textfield.delegate = self.delegateObject;
于 2012-05-31T20:44:19.650 に答える
1

問題は、Cocoa (Touch) のデリゲートは通常保持されないということです。これにより、リテイン サイクルが防止されます。しかし、これは、オブジェクトの使用が終わったときにオブジェクトを解放するために、別の何かがオブジェクトへの参照を保持する必要があることも意味します。そうしないと、オブジェクトがリークされるだけです。これが、このパターンでデリゲート関係が機能する方法です。

メソッドが機能する理由getDelegateは、デリゲートへの参照が静的変数delに格納されているためです。これにより、ARC はオブジェクトを解放できなくなります。

于 2012-05-31T16:21:52.943 に答える
0

さて、「理由」は、UITextFieldプロパティdelegateが次のように宣言されているためです。

@property(nonatomic, assign) id<UITextFieldDelegate> delegate

(クラス リファレンスを参照してください。)

宣言されたプロパティassignは、「セッターが単純な割り当てを使用する」ことを意味し、したがって、保持 (または割り当てられていない場合は解放) などのメモリ管理機能を実装しません。( Objective-C プログラミング言語、宣言されたプロパティを参照)

于 2012-05-31T18:48:04.093 に答える