web-dev-qa-db-ja.com

ARCの下ではIBOutletを強くするべきか弱くするべきですか?

ARCを使用してiOS 5専用に開発しています。 IBOutletsからUIViews(およびサブクラス)はstrongまたはweakのどちらにすべきですか?

以下:

@property (nonatomic, weak) IBOutlet UIButton *button;

これをすべて取り除くでしょう:

- (void)viewDidUnload
{
    // ...
    self.button = nil;
    // ...
}

これをやっている問題はありますか? 'Interface Builder'エディタから直接ヘッダに接続するときに作成される自動的に生成されたプロパティがそうであるように、テンプレートはstrongを使用しています、しかしなぜ? UIViewControllerは、そのサブビューを保持するstrongへのview参照をすでに持っています。

535
hypercrypt

Appleから現在推奨されているベストプラクティスは、保持サイクルを回避するためにweakが特に必要でない限り、IBOutletsがstrongであることです。 Johannesが前述したように、これはアップルエンジニアが言ったWWDC 2015からの「Interface BuilderでのUIデザインの実装」セッションでコメントされました:

そして、私が指摘したい最後のオプションはストレージタイプです。これは強いか弱いかのどちらかです。一般に、アウトレットをサブビューまたはビュー階層によって常に保持されるわけではない制約に接続する場合は、アウトレットを強くする必要があります。あなたが本当にアウトレットを弱くする必要がある唯一の時はあなたがビュー階層をバックアップする何かを参照するカスタムビューを持っているならば、そしてそれは一般的にはお勧めできません。

私はTwitterでIBチームのエンジニアにこれについて尋ねました、そして、彼は強いがデフォルトであるべきでありそして開発者向け文書が更新されていることを確認しました。

https://Twitter.com/_danielhall/status/620716996326350848https://Twitter.com/_danielhall/ status/620717252216623104

225
Daniel Hall

警告、期限切れの回答:この回答は、WWDC 2015に従って最新ではありません。正しい回答については、 承認済み回答を参照してください (ダニエルホール)この答えは記録に残るでしょう。


開発者ライブラリ から要約すると、

実用的な観点から、iOSとOS Xでは、アウトレットは宣言されたプロパティとして定義されるべきです。 File's Ownerからnibファイルのトップレベルオブジェクト(またはiOSではストーリーボードシーン)までのアウトレットを除いて、アウトレットは一般的に弱いはずです。そのため、作成したアウトレットは通常、デフォルトでは弱くなります。

  • たとえば、View ControllerのビューやWindow Controllerのウィンドウのサブビューに作成するアウトレットは、所有権を意味しないオブジェクト間の任意の参照です。

  • 強力なアウトレットは、フレームワーククラス(UIViewControllerのビューアウトレット、NSWindowControllerのウィンドウアウトレットなど)によって頻繁に指定されます。

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
448

ドキュメントではサブビューのプロパティにweakを使用することを推奨していますが、iOS 6以降は代わりにstrong(デフォルトの所有権修飾子)を使用することをお勧めします。UIViewControllerの変更により、ビューはもうアンロードされません。

  • IOS 6より前のバージョンでは、コントローラのビューのサブビューへの強力なリンクを保持している場合、View Controllerのメインビューがアンロードされても、View Controllerが存在する限りサブビューに保持されていました。
  • IOS 6以降、ビューはもうアンロードされませんが、一度ロードされてからコントローラが存在する限り固定されます。とても強い性質は重要ではありません。また、強力な参照グラフを指すので、強力な参照サイクルは作成されません。

それは言った、私は使用の間で引き裂かれている

@property (nonatomic, weak) IBOutlet UIButton *button;

そして

@property (nonatomic) IBOutlet UIButton *button;

iOS 6以降の場合

  • weakを使うことは、コントローラーがボタンの所有権を望んでいないことを明確に示しています。

  • しかし、iOS 6ではweakを省略してもビューをアンロードしなくても問題はなく、短くなります。もっと速いと指摘する人もいるかもしれませんが、私はまだweakIBOutletsのために遅すぎるアプリケーションに遭遇していません。

  • weakを使用しないと、エラーとして認識される可能性があります。

結論:iOS 6以降、ビューのアンロードを使用しない限り、これを間違えることはもうありません。パーティーの時間だ。 ;)

48
Tammo Freese

私はそれについて何の問題も見ません。 ARC以前、私はIBOutletsを常にassignとしていました。あなたがそれらをweakにするなら、あなたが指摘するように、あなたはviewDidUnloadの中でそれらをゼロにする必要はないはずです。

1つの注意点:ARCプロジェクトでiOS 4.xをサポートすることはできますが、そうする場合はweakを使用できないため、それらをassignにする必要があります。その場合は、参照をnilにする必要があります。ぶら下がりポインタを避けるためのviewDidUnload。これは私が経験したぶら下がっているポインターバグの例です:

UIViewControllerには、郵便番号用のUITextFieldがあります。これはCLLocationManagerを使用してユーザーの位置を逆ジオコーディングし、郵便番号を設定します。これがデリゲートコールバックです:

-(void)locationManager:(CLLocationManager *)manager
   didUpdateToLocation:(CLLocation *)newLocation
          fromLocation:(CLLocation *)oldLocation {
    Class geocoderClass = NSClassFromString(@"CLGeocoder");
    if (geocoderClass && IsEmpty(self.Zip.text)) {
        id geocoder = [[geocoderClass alloc] init];
        [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
            if (self.Zip && IsEmpty(self.Zip.text)) {
                self.Zip.text = [[placemarks objectAtIndex:0] postalCode];
            }
        }];    
    }
    [self.locationManager stopUpdatingLocation];
}

適切なタイミングでこのビューを閉じ、self.ZipをviewDidUnloadに入れなかった場合、デリゲートコールバックはself.Zip.textに不正なアクセス例外をスローする可能性があります。

34

IOSの開発では、NIBの読み込みはMacの開発とは少し異なります。

Macの開発では、IBOutletは通常弱い参照です。NSViewControllerのサブクラスがある場合はトップレベルのビューだけが保持され、コントローラの割り当てを解除するとそのすべてのサブビューとアウトレットは自動的に解放されます。

UiViewControllerはキー値コーディングを使用して、強力な参照を使用してアウトレットを設定します。そのため、UIViewControllerの割り当てを解除すると、トップビューの割り当ても自動的に解除されますが、deallocメソッドですべてのアウトレットの割り当ても解除する必要があります。

Big Nerd Ranch からのこの記事では、このトピックをカバーし、なぜIBOutletで強力な参照を使用するのが適切でないのか説明します。この場合はAppleが推奨しています。

20
Giuseppe

パフォーマンス上の理由から、IBOutletは強力であるべきです。 iOS 9の ストーリーボードリファレンス、Strong IBOutlet、Scene Dockを参照してください

この段落で説明したように、View Controllerのビューのサブビューへのアウトレットは弱くなる可能性があります。これらのサブビューはすでにnibファイルの最上位オブジェクトによって所有されているためです。ただし、アウトレットがウィークポインタとして定義されていてポインタが設定されている場合、ARCはランタイム関数を呼び出します。

id objc_storeWeak(id *object, id value);

これは、オブジェクト値をキーとして使用して、ポインタ(オブジェクト)をテーブルに追加します。このテーブルはウィークテーブルと呼ばれます。 ARCはこのテーブルを使用して、アプリケーションのすべての脆弱なポインタを格納します。これで、オブジェクト値の割り当てが解除されると、ARCは弱いテーブルを繰り返し処理し、弱い参照をnilに設定します。あるいは、ARCは以下を呼び出すことができます。

void objc_destroyWeak(id * object)

その後、オブジェクトは登録解除され、objc_destroyWeakが再度呼び出します。

objc_storeWeak(id *object, nil)

弱い参照に関連付けられているこの記帳は、強い参照のリリースよりも2〜3倍長くかかる可能性があります。そのため、弱い参照はランタイムに対してオーバーヘッドをもたらしますが、アウトレットを強いと定義するだけで回避できます。

Xcode 7では、strongが推奨されています

WWDC 2015セッション407 Interface BuilderでのUIデザインの実装 を見ている場合は、( http://asciiwwdc.com/2015/sessions/のトランスクリプトをお勧めします) 407

そして、私が指摘したい最後のオプションはストレージタイプです。これは強いか弱いかのどちらかです。

一般に、アウトレットをサブビューまたはビュー階層によって常に保持されるわけではない制約に接続する場合は、アウトレットを強くする必要があります。

あなたが本当にアウトレットを弱くする必要がある唯一の時はあなたがビュー階層をバックアップする何かを参照するカスタムビューを持っているならば、そしてそれは一般的にはお勧めできません。

だから私は強いを選択するつもりだと私は私のアウトレットを生成します接続をクリックします。

20
onmyway133

ここで指摘したいことの1つは、AppleエンジニアがWWDC 2015のビデオでここで述べていることにもかかわらずです。

https://developer.Apple.com/videos/play/wwdc2015/407/

Appleはこの問題について考えを変え続けています。これは、この質問に対する正しい答えは1つもないことを示しています。 Appleエンジニアでさえこのテーマで分裂していることを示すために、Appleの最新のサンプルコードを見てください。

このApple Payの例では、weakを使用しています: https://developer.Apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_Swift.html#//Apple_ref/ doc/uid/TP40016175-Emporium_ProductTableViewController_Swift-DontLinkElementID_8

このピクチャー・イン・ピクチャーの例のように: https://developer.Apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_Swift.html#//Apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_Swift-DontLinkElementID_4

リスターの例と同じように: https://developer.Apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_Swift.html#//Apple_ref/doc/uid/TP40014701-Lister_ListCell_Swift -DontLinkElementID_57

コアロケーションの例と同様: https://developer.Apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_Swift.html#//Apple_ref/doc/uid/TP40016176- Potloc_PotlocViewController_Swift-DontLinkElementID_6

View Controllerのプレビュー例と同様に、 https://developer.Apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_Swift.html#//Apple_ref/doc/uid/TP40016546 -Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_Swift-DontLinkElementID_5

HomeKitの例と同様: https://developer.Apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_Swift.html#//Apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Set_Action_SetsAction -DontLinkElementID_23

これらはすべてiOS 9用に完全に更新されており、すべて弱いコンセントを使用しています。このことから、A。問題は、一部の人々が考えているほど単純ではないことがわかります。 B. Appleは心を繰り返し変えました。C。あなたが幸せにするものなら何でも使用できます:)

ポール・ハドソン(www.hackingwithsift.comの著者)に、説明とこの回答への参照を与えてくれたことに感謝します。

これで主題が少し良くなることを願っています!

世話をする。

16
syedfa

WWDC 2015から Interface BuilderでUIデザインを実装する に関するセッションがあります。 32分頃に彼はあなたがいつもあなたの@IBOutletを強くしたいと言います。

9
Johannes

IBOutletCollection@property (strong, nonatomic)であるべきです。

6
landonandrey

何年かの間に何かが変わったように見えます、そして今、Appleは一般的に強いものを使うことを勧めます。 WWDCセッションの証拠は セッション407 - Interface BuilderでのUIデザインの実装 で、32:30に始まります。彼の言ったことからの私のメモは次のとおりです(正確ではないにしても、ほとんど彼を引用しています)。

  • アウトレット接続は一般に、ビュー階層によって常に保持されているわけではないサブビューまたは制約を接続する場合は特に強くなります

  • ビュー階層内でバックアップされているものへの参照を持つカスタムビューを作成するときには、弱いアウトレット接続が必要になることがあります。一般的にはお勧めできません

他のワードでは、私たちのカスタムビューのいくつかがビュー階層の上のいくつかのビューと保持サイクルを作らない限り、それは今や常に強いはずです。

編集:

質問をする人もいます。それを強力な参照と一緒にしても、ルートビューコントローラと所有ビューが参照を保持するため、保持サイクルは作成されませんか。それともなぜそれが起きたのでしょうか。 xibからnibがどのように作成されるかを説明しているとき、私はその答えがこの講演の前半にあると思います。 VC用とビュー用に別々のペン先が作成されています。これが彼らが勧告を変える理由であるかもしれないと思います。それでも、Appleからより深い説明を得るのはいいだろう。

5
Julian Król

最も重要な情報は次のようになると思います。xibの要素は自動的にビューのサブビューに含まれます。サブビューはNSArrayです。 NSArrayはその要素を所有しています。などはそれらに強いポインタを持っています。そのため、ほとんどの場合、別の強力なポインタを作成したくありません(IBOutlet)。

ARCを使えば、viewDidUnloadで何もする必要はありません。

4
kraag22