ios - kit - mac os api




IBOutlets는 ARC 하에서 강하거나 약합니까? (8)

Apple의 현재 권장되는 우수 사례는 보유주기를 피하기 위해 약한 것이 특별히 필요하지 않는 한 IBOutlet을 강하게 만드는 것입니다. 요하네스가 위에서 언급했듯이, 이것은 Apple 엔지니어가 말한 WWDC 2015의 "Interface Builder에서 UI 디자인 구현"세션에서 언급되었습니다.

마지막으로 강조하고자하는 옵션은 저장 유형입니다. 저장 유형은 강하거나 약합니다. 일반적으로 콘센트를 강하게 만들어야합니다. 특히 콘센트를 하위 뷰에 연결하거나 뷰 계층 구조에서 항상 유지되지 않을 수있는 제약 조건에 연결하는 경우가 그렇습니다. 콘센트를 약하게 만들 필요가있는 유일한 경우는보기 계층 구조를 백업하는 사용자 지정보기가 있고 일반적으로 권장되지 않는 경우입니다.

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

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

ARC를 사용하여 iOS 5 전용으로 개발 중입니다. UIView (및 하위 클래스)에 IBOutlet strong 또는 weak 해야합니까?

다음과 같은:

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

이 모든 것을 제거 할 수 있을까요?

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

이 문제가 있습니까? 템플릿은 '인터페이스 빌더'편집기에서 헤더에 직접 연결할 때 생성되는 자동 생성 된 속성과 같이 strong 을 사용하지만 그 이유는 무엇입니까? UIViewController 이미 하위 view 를 유지하는 뷰에 대한 strong 참조를 가지고 있습니다.



가장 중요한 정보는 다음과 같습니다. xib의 요소는 자동으로 하위 뷰에 있습니다. 하위보기는 NSArray입니다. NSArray는 그것의 요소를 소유하고 있습니다. 등 강한 포인터가 그들에있다. 따라서 대부분의 경우 다른 강력한 포인터 (IBOutlet)를 만들고 싶지 않습니다.

ARC를 사용하면 viewDidUnload 에서 아무 것도 할 필요가 없습니다.


나는 그 어떤 문제도 보지 못한다. Pre-ARC, IBOutlets는 이미 수퍼 뷰로 유지되어 있으므로 항상 assign 했습니다. 만약 당신이 그들을 weak 만들면, 당신이 지적한 것처럼 viewDidUnload에서 그들을 제쳐두면 안된다.

한 가지주의 사항 : ARC 프로젝트에서 iOS 4.x를 지원할 수는 있지만 그렇게하면 weak 사용할 수 없으므로 assign 을해야 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];
}

적절한 시점에이 뷰를 닫고 viewDidUnload에서 viewDidUnload 하지 않으면 delegate 콜백이 self.zip.text에 잘못된 액세스 예외를 throw 할 수 있다는 것을 알게되었습니다.


여기서 지적하고자하는 것은 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

이 PIP (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

Lister 예제와 마찬가지로 : 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_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_Sets_ActionSetViewController_swift-DontLinkElementID_23

그것들은 모두 iOS 9 용으로 완전히 업데이트되었으며 모두 약점을 사용합니다. 이 점에서 우리는 A.을 배웁니다. 어떤 사람들은 그 문제를 쉽게 풀어 내지 못합니다. B. 애플은 반복적으로 마음을 바꿨다. C. 무엇이든지 행복하게 사용할 수있다. :)

Paul Hudson (www.hackingwithsift.com의 저자)에게 감사의 말을 전하며이 답변에 대한 참고서를 보내 주신 것에 대해 특별히 감사드립니다.

이렇게하면 주제가 좀 더 명확 해지기를 바랍니다.

조심해.


IBOutlet 은 성능상의 이유로 강해야합니다. Storyboard Reference, Strong IBOutlet, iOS 9의 Scene Dock보기

이 단락에서 설명했듯이 View Controller 뷰의 하위 뷰에 대한 아웃렛은 약식 일 수 있습니다. 서브 뷰는 이미 nib 파일의 최상위 객체가 소유하고 있기 때문입니다. 그러나 아울렛이 weak 포인터로 정의되고 포인터가 설정되면 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 에서 http://asciiwwdc.com/2015/sessions/407 내용을 제안합니다.

마지막으로 강조하고자하는 옵션은 저장 유형입니다. 저장 유형은 강하거나 약합니다.

일반적으로 콘센트를 강하게 만들어야합니다. 특히 콘센트를 하위 뷰에 연결하거나 뷰 계층 구조에서 항상 유지되지 않을 수있는 제약 조건에 연결하는 경우가 그렇습니다.

콘센트를 약하게 만들 필요가있는 유일한 경우는보기 계층 구조를 백업하는 사용자 지정보기가 있고 일반적으로 권장되지 않는 경우입니다.

그래서 나는 강하게 선택하고 연결을 클릭하면 콘센트가 생성됩니다.


경고, 답답함 :이 답변은 WWDC 2015에 따라 최신이 아닙니다. 정답은 위의 인정 된 답변 (Daniel Hall)을 참조하십시오. 이 대답은 기록을 유지할 것입니다.

개발자 라이브러리 요약 :

실용적인 관점에서 볼 때 iOS 및 OS X에서 아웃렛은 선언 된 속성으로 정의해야합니다. 아웃렛은 일반적으로 File 's Owner에서 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에서 상처를 입히지 않으며 더 짧습니다. 어떤 사람들은 그것도 더 빠르다고 지적 할 수는 있지만, IBOutletweak 때문에 너무 느린 앱을 아직 보지 못했습니다.

  • weak 사용하지 않으면 오류로 인식 될 수 있습니다.

최종선 : iOS 6 이후로 우리는 뷰 언로드를 사용하지 않는 이상 더 이상이 오류를 얻을 수 없습니다. 파티 할 시간이야. ;)







automatic-ref-counting