565

私はARCを使用してiOS5専用に開発しています。IBOutletsからUIViews(およびサブクラス)はまたはである必要がありますstrongか?weak

以下:

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

このすべてを取り除くだろう:

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

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

4

11 に答える 11

454

警告、古い回答:この回答はWWDC 2015に従って最新ではありません。正解については、上記の承認された回答(Daniel Hall)を参照してください。この回答は記録に残ります。


開発者ライブラリから要約:

実用的な観点から、iOSおよびOS Xでは、アウトレットは宣言されたプロパティとして定義する必要があります。ファイルの所有者からnibファイル(またはiOSではストーリーボードシーン)のトップレベルオブジェクトまでのアウトレットを除いて、アウトレットは一般的に弱くする必要があります。したがって、作成するアウトレットは通常、デフォルトで弱くなります。理由は次のとおりです。

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

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

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
于 2011-10-11T16:10:20.873 に答える
275

Appleが現在推奨しているベストプラクティスは、保持サイクルを回避するために特に弱い必要がない限り、IBOutletsを強力にすることです。Johannesが前述したように、これはWWDC2015の「ImplementingUIDesigns in Interface Builder」セッションでコメントされ、Appleのエンジニアは次のように述べています。

そして私が指摘したい最後のオプションはストレージタイプであり、それは強いか弱いかのどちらかです。一般に、アウトレットをサブビューまたはビュー階層によって常に保持されるとは限らない制約に接続する場合は特に、アウトレットを強力にする必要があります。アウトレットを弱くする必要があるのは、ビュー階層のバックアップを参照するカスタムビューがある場合のみであり、一般的には推奨されません。

これについてTwitterでIBチームのエンジニアに尋ねたところ、彼はstrongをデフォルトにする必要があり、開発者向けドキュメントが更新されていることを確認しました。

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

于 2015-07-14T00:59:00.750 に答える
51

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

  • iOS 6より前では、コントローラーのビューのサブビューへの強力なリンクを維持している場合、ビューコントローラーのメインビューがアンロードされた場合、ビューコントローラーが存在する限りサブビューを保持していました。
  • iOS 6以降、ビューはアンロードされなくなりましたが、一度ロードされてから、コントローラーが存在する限りそのままになります。したがって、強力なプロパティは重要ではありません。また、強力な参照グラフを指すため、強力な参照サイクルは作成されません。

そうは言っても、私は使用することの間で引き裂かれています

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

@property (nonatomic) IBOutlet UIButton *button;

iOS 6以降:

  • を使用するweakと、コントローラーがボタンの所有権を望まないことが明確に示されます。

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

  • 使用しweakないとエラーとして認識される場合があります。

結論:iOS 6以降、ビューのアンロードを使用しない限り、これを誤解することはできません。パーティーの時間。;)

于 2013-12-10T21:54:30.393 に答える
34

何の問題もありません。ARC以前、私は常にIBOutletsを作成してきました。これはassign、それらがすでにスーパービューによって保持されているためです。あなたがそれらを作るならばweak、あなたが指摘するように、あなたはviewDidUnloadでそれらをゼロにする必要はないはずです。

注意点:ARCプロジェクトでiOS 4.xをサポートできますが、サポートする場合は使用できないためweak、作成する必要がassignあります。その場合でも、参照をゼロにし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をnilしなかったviewDidUnload場合、デリゲートコールバックがself.zip.textで不正アクセス例外をスローする可能性があることがわかりました。

于 2011-10-07T22:34:34.493 に答える
25

IBOutletパフォーマンス上の理由から、強力である必要があります。iOS 9のストーリーボードリファレンス、Strong IBOutlet、SceneDockを参照してください

この段落で説明したように、ビューコントローラのビューのサブビューへのアウトレットは弱い可能性があります。これらのサブビューはすでに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

WWDC2015セッション407InterfaceBuilderでのUIデザインの実装を見ると、( http://asciiwwdc.com/2015/sessions/407からのトランスクリプト)が示唆されています。

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

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

アウトレットを弱くする必要があるのは、ビュー階層のバックアップを参照するカスタムビューがある場合のみであり、一般的には推奨されません。

だから私は強いものを選び、接続をクリックしてアウトレットを生成します。

于 2015-11-04T04:27:16.930 に答える
20

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

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

UiViewControllerは、Key Value Codingを使用して、強力な参照を使用してアウトレットを設定します。したがって、UIViewControllerの割り当てを解除すると、上面ビューの割り当てが自動的に解除されますが、deallocメソッドですべてのアウトレットの割り当てを解除する必要もあります。

Big Nerd Ranchからのこの投稿では、このトピックを取り上げ、IBOutletで強力な参照を使用することが適切でない理由も説明しています(この場合、Appleが推奨している場合でも)。

于 2011-10-10T16:02:21.260 に答える
18

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

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

Appleはこの問題について考えを変え続けており、この質問に対する正しい答えは1つではないことを示しています。Appleのエンジニアでさえこの問題について意見が分かれていることを示すために、Appleの最新のサンプルコードを見てください。弱いものを使う人もいれば、使わない人もいます。

このApplePayの例では、weakを使用してい ます。

このピクチャーインピクチャーの例のように: 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

ビューコントローラのプレビューの例と同様に: https ://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_

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_Sets_ActionSetViewController_swift-Dont

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

説明とこの回答の参照をくれたPaulHudson(www.hackingwithsift.comの作成者)に特に感謝します。

これが主題をもう少し明確にすることを願っています!

気をつけて。

于 2016-05-05T21:25:41.610 に答える
10

WWDC 2015から、InterfaceBuilderでのUIデザインの実装に関するセッションがあります。32分のマークのあたりで、彼はあなたが常にあなたの@IBOutlet 強いものを作りたいと言います。

于 2015-07-09T13:11:03.050 に答える
6

注意してください、IBOutletCollectionする必要があります@property (strong, nonatomic)

于 2014-03-25T13:02:53.187 に答える
5

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

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

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

他のワードでは、カスタムビューの一部が、ビュー階層の上位にあるビューの一部で保持サイクルを作成しない限り、常に強力である必要があります。

編集 :

質問をする人もいます。ルートビューコントローラーと所有ビューがそれへの参照を保持するため、強力な参照を保持しても保持サイクルは作成されませんか?それとも、なぜそれが起こったのですか?答えは、この話の早い段階で、xibからニブがどのように作成されるかを説明していると思います。VC用とビュー用に別々のペン先が作成されています。これが彼らが推奨事項を変更する理由かもしれないと思います。それでも、Appleからより深い説明を得るのはいいことだろう。

于 2015-08-07T08:28:38.960 に答える
4

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

そしてARCを使えば、何もする必要はありませんviewDidUnload

于 2012-12-04T14:49:28.657 に答える