3

UIViewController で次のプロパティを定義しています。

@property (nonatomic, strong) UIButton *strongButton;
@property (nonatomic, weak) UIButton *weakButton;

これらのプロパティは、Interface Builder では設定されません (つまり、コードで明示的に設定しない限り、常に nil のままです)。

また、UIButton にカテゴリを追加して、いつ割り当てが解除されたかを正確に把握できるようにしました。

@implementation UIButton (test)
- (void)dealloc { NSLog(@"Dealloc called."); }
@end

viewDidLoadUIViewControllerに次のコードがあります。

self.strongButton = [[UIButton alloc] init];
self.weakButton = self.strongButton;
NSAssert(self.weakButton != nil, @"A: Weak button should not be nil.");
NSLog(@"Setting to nil");
self.strongButton = nil;
NSLog(@"Done setting to nil");
NSAssert(self.weakButton == nil, @"B: Weak button should be nil.");

そのコードを実行すると、2 番目のアサーション (B) で失敗します。ログには次のように表示されます。

  • ゼロに設定
  • nil に設定完了
  • * -[ViewController viewDidLoad] でのアサーションの失敗
  • *キャッチされない例外「NSInternalInconsistencyException」が原因でアプリを終了します。理由:「B: 弱いボタンは nil にする必要があります。」

ただし、最初のアサーションをコメントアウトすると、次のようになります。

self.strongButton = [[UIButton alloc] init];
self.weakButton = self.strongButton;
//NSAssert(self.weakButton != nil, @"A: Weak button should not be nil.");
NSLog(@"Setting to nil");
self.strongButton = nil;
NSLog(@"Done setting to nil");
NSAssert(self.weakButton == nil, @"B: Weak button should be nil.");

ログでこれを使用すると、コードは正常に実行されます。

  • ゼロに設定
  • 割り当て解除が呼び出されました。
  • nil に設定完了

最初のシナリオで、dealloc が適切なタイミングで呼び出されていないことに注意してください。

最初の NSAssert がこの奇妙な動作を引き起こしているのはなぜですか? これはバグですか、それとも何か間違っていますか?

(私はiOS 6.1を使用しています)

4

1 に答える 1

7

弱い変数を読み取ると、ポイント先のオブジェクトが保持され、自動解放される場合があります。オブジェクトは、少なくとも現在の自動解放プールの間は存続します。

あなたの場合、最初NSAssert()に弱い変数を読み取ります。ボタン オブジェクトは保持され、自動解放されます。設定self.strongButton=nilによってボタンの割り当てが解除されることはありません。これは、ボタンが自動解放プールでまだ有効であるため、weak 変数が nil にならないためです。

をコメントアウトするNSAssert()と、weak 変数が読み取られなくなり、ボタンが保持されず自動解放されなくなり、実際には を設定すると終了しますself.strongButton=nil

于 2013-07-30T01:26:06.737 に答える