[ios] ARC에서 IBOutlet이 강하거나 약해야합니까?

ARC를 사용하여 iOS 5 전용으로 개발 중입니다. 한다은 IBOutlet에이야 UIView의 (및 서브 클래스) 일 strong이나 weak?

다음과 같은:

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

이 모든 것을 제거 할 것입니다 :

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

이 작업에 문제가 있습니까? 템플릿은 strong‘Interface Builder’편집기에서 헤더에 직접 연결할 때 자동으로 생성 된 속성 을 그대로 사용 하지만 왜 그럴까요? 은 UIViewController이미 가지고 strong그 참조 view그 파단을 유지한다.



답변

Apple에서 현재 권장하는 모범 사례 는 유지주기를 피하기 위해 특별히 약한 것이 필요 하지 않은 한 IBOutlets를 강력하게 하는 것입니다. Johannes가 위에서 언급했듯이, 이는 Apple Engineer가 WWDC 2015의 “Interface Builder에서 UI 디자인 구현”세션에서 언급 한 내용입니다.

마지막으로 지적하고자하는 옵션은 강력하거나 약한 스토리지 유형입니다. 일반적으로 콘센트를 하위 뷰에 연결하거나 항상보기 계층 구조에 의해 유지되지 않는 구속 조건에 연결하는 경우 콘센트를 강하게 만들어야합니다. 실제로 아울렛을 약화시켜야하는 유일한 시점은보기 계층 구조를 백업하는 항목을 참조하는 사용자 정의보기가 있고 일반적으로 권장하지 않는 경우입니다.

나는 트위터에서 IB 팀의 엔지니어에게 이것에 대해 물었고 그는 기본값 이 강력 해야하며 개발자 문서가 업데이트되고 있음을 확인했습니다 .

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



답변

경고, 오래된 답변 :이 답변은 WWDC 2015에 따른 최신 정보가 아닙니다. 정답은 위의 수락 된 답변 (Daniel Hall)을 참조하십시오. 이 답변은 기록을 유지합니다.


개발자 라이브러리 에서 요약 :

실용적인 관점에서, iOS 및 OS X 콘센트는 선언 된 속성으로 정의해야합니다. 아웃렛은 일반적으로 파일 소유자에서 nib 파일 (또는 iOS의 경우 스토리 보드 장면)의 최상위 레벨 오브젝트에 이르는 것을 제외하고는 약해야합니다. 따라서 생성하는 콘센트는 일반적으로 다음과 같은 이유로 기본적으로 약합니다.

  • 예를 들어, 뷰 컨트롤러보기 또는 창 컨트롤러 창의 하위보기에 대해 생성하는 아울렛은 소유권을 의미하지 않는 개체 간의 임의 참조입니다.

  • 강력한 콘센트는 프레임 워크 클래스 (예 : UIViewController의보기 콘센트 또는 NSWindowController의 창 콘센트)에 의해 지정됩니다.

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

답변

이 문서에서는 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부터 뷰 언로드를 사용하지 않는 한 더 이상 잘못 얻을 수 없습니다. 파티 시간. 😉


답변

나는 그것에 아무런 문제가 보이지 않습니다. 사전 아크, 나는 항상 assign그들의 IBOutlets를 만들었습니다 . 왜냐하면 그들은 이미 슈퍼 뷰에 의해 유지되기 때문입니다. 당신이 그 (것)을하면 weak, 당신은 당신이 지적으로, viewDidUnload에서 그들을 nil을 할 필요가 없습니다.

한 가지주의 사항 : 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을 생략하지 않으면 viewDidUnload대리자 콜백이 self.zip.text에서 잘못된 액세스 예외를 던질 수 있음을 발견했습니다.


답변

IBOutlet성능상의 이유로 강력해야합니다. 참조 스토리 보드 참조, 강한 함께 IBOutlet, 아이폰 OS의 장면 독 (9)

이 단락에서 설명했듯이 뷰 컨트롤러 뷰의 하위 뷰에 대한 출구는 약한 것일 수 있습니다. 이러한 하위 뷰는 nib 파일의 최상위 개체가 이미 소유하고 있기 때문입니다. 그러나 Outlet이 약한 포인터로 정의되고 포인터가 설정된 경우 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 UI 디자인 구현 을 볼 경우 ( http://asciiwwdc.com/2015/sessions/407의 스크립트 )

마지막으로 지적하고자하는 옵션은 강력하거나 약한 스토리지 유형입니다.

일반적으로 콘센트를 하위보기 또는 항상보기 계층 구조에 의해 유지되지 않는 구속 조건에 연결하는 경우 콘센트를 강하게 만들어야합니다.

실제로 아울렛을 약화시켜야하는 유일한 시점은보기 계층 구조를 백업하는 항목을 참조하는 사용자 정의보기가 있고 일반적으로 권장하지 않는 경우입니다.

강력하게 선택하고 연결을 클릭하여 콘센트를 생성합니다.


답변

iOS 개발에서 NIB 로딩은 Mac 개발과 약간 다릅니다.

Mac 개발에서 IBOutlet은 일반적으로 약한 참조입니다. NSViewController의 서브 클래스가있는 경우 최상위 뷰만 유지되며 컨트롤러 할당을 해제하면 모든 서브 뷰와 콘센트가 자동으로 해제됩니다.

UiViewController는 Key Value Coding을 사용하여 강력한 참조를 사용하여 콘센트를 설정합니다. 따라서 UIViewController를 할당 해제하면 상위 뷰가 자동으로 할당 해제되지만 dealloc 메소드에서 모든 콘센트를 할당 해제해야합니다.

Big Nerd Ranch의이 글 에서이 주제를 다루고 IBOutlet에서 강력한 참조를 사용하는 것이 왜 좋은 선택이 아닌지 설명합니다 (이 경우 Apple에서 권장하더라도).


답변

여기서 지적하고 싶은 것은 애플 엔지니어들이 WWDC 2015 비디오에서 언급 한 내용에도 불구하고

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

애플은이 주제에 대한 생각을 계속 바꾸어이 질문에 대한 정답이 하나도 없다고 말합니다. Apple 엔지니어조차도이 주제에 대해 나뉘어져 있음을 보여주기 위해 Apple의 최신 샘플 코드를 살펴보면 일부 사람들은 약한 것을 사용하고 그렇지 않은 사람들도 있습니다.

이 Apple Pay 예제는 약한 것을 사용합니다.
https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8

이 picture-in-picture 예와 마찬가지로
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_PreviewUsingDelegate_PreviewUsingDelegate_PreviewUsingDelegate_PreviewUsingView

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_ActionntViewLink_Sets_ActionntViewElement_

모두 iOS 9 용으로 완전히 업데이트되었으며 모두 약한 콘센트를 사용합니다. 이것으로부터 우리는 A를 알게됩니다. 어떤 사람들은 그것을 만드는 것처럼 간단하지 않습니다. B. 애플은 마음이 반복적으로 바뀌었고 C. 당신은 행복하게 만드는 것을 사용할 수 있습니다 🙂

설명을 해준 Paul Hudson (www.hackingwithsift.com의 저자)에게 특별한 감사의 말을 전합니다.

이것이 주제를 조금 더 명확하게하기를 바랍니다.

조심해