1

우리 모두는 블록이 캡처 한 객체를 보유한다는 것을 알고 있습니다. 또한 객체에 대한 약한 참조를 블록으로 전달하여이를 피할 수 있음을 알 수 있습니다. 그런데 왜이 방법으로 작동합니까? 객체를 유지한다는 것은 보유 수를 1로 늘리는 것을 의미합니다. 약한 참조를 전달하는 것이 왜 다른가요? 약하거나 강한 개체는 여전히 같은 개체를 가리키고이 개체의 보유 개수는 블록 단위로 증가합니다. 내가 맞습니까? 그렇다면 블록 내부의 객체에 약한 참조를 전달하면 객체의 보유 개수가 증가하지 않는 이유는 무엇입니까? 어떻게 작동합니까?블록에 약한 참조를 전달하면 왜 객체가 유지되지 않습니까?

답변

2

당신은 종류의 시간에 해당하는 캡처 된 변수의 값으로 초기화됩니다 캡처 된 각 변수에 대한 "인스턴스 변수"가 대상으로 블록 생각할 수 블록이 작성됩니다.

ARC에서 블록의 "인스턴스 변수"는 해당 캡처 변수와 동일한 소유권 지정자를가집니다. 따라서 객체 포인터 유형의 캡처 된 변수가 __strong (기본값) 인 경우 블록의 "인스턴스 변수"는 __strong이기 때문에 블록 수명 동안 지정된 객체를 유지합니다. 객체 포인터 유형의 캡처 된 변수가 __strong 인 경우 블록의 "인스턴스 변수"는 __weak이기 때문에 가리키는 객체에 대한 약한 참조가 아닙니다.

1

클로저가 일반적으로 어떻게 작동하는지 이해하고 싶을 수도 있습니다.

var name = "NSNoName" 
NSLog("Original name: %@ <%p>", name, name) 

let takeName: (String) -> Void ->() = { 
    name in 
    return { 
     NSLog("Name inside block: %@ <%p>", name, name) 
    } 
} 

let returnName = takeName(name) 
name = "NSNoFame" 
returnName() 

NSLog("Changed name: %@ <%p>", name, name) 

처음 이름 변수의 값이 "NSNoName"입니다, 예를 들어 다음과 같은 코드를 가지고. 이 때 이름을 인쇄하면 결과가 나타납니다.

Original name: NSNoName <0x7f8fb86004a0> 

문자열을 매개 변수로 사용하는 간단한 closure가 있습니다. 같은 이름의 객체로 클로저를 호출합니다. 결과적으로 블록은 객체의 자체 복사본을 만듭니다. 그런 다음 계속해서 이름을 개체로 변경합니다. 이제 블록을 호출하면 이름이 인쇄되고 블록은 전달 된 동일한 원래 값을 갖습니다. 그러나 객체가 다르다. 즉, 블록이 동일한 값을 가진 새로운 객체를 생성했다는 것을 의미한다.

Name inside block: NSNoName <0x7f8fb8602510> 

마지막 NSLog

, 이것은 당신이 약한 참조를 만들기 위해 블록을 이야기하려는 이유는

Changed name: NSNoFame <0x7f8fb8603ae0> 

, 이미 변경되어 있기 때문에 다른 값을 출력하고 몇 가지 다른 값을 가지고 객체에 더 이상 존재하지 않는 경우, nil 블록 내부에 참조 객체가 생성됩니다.

은 목표 C와 동안,하지만 조금 다른 것 같다

@interface TestViewController() 

@property (nonatomic, strong) NSString *name; 

@end 

@implementation TestViewController 


- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.name = @"NSNoName"; 

    NSLog(@"Original name: %@ <%p>", self.name, self.name); 

    typedef void(^ReturnNameBlock)(); 

    ReturnNameBlock (^takeName)(NSString*) = ^ReturnNameBlock(NSString *name) { 
     return ^{ 
      NSLog(@"Name inside block: %@ <%p>", name, name); 
     }; 
    }; 

    ReturnNameBlock returnName = takeName(self.name); 

    self.name = @"NSNoFame"; 

    returnName(); 

    NSLog(@"Changed name: %@ <%p>", self.name, self.name); 

} 

@end 

내 로그는 다음과 같이 나타납니다

Original name: NSNoName <0x103ae34c0> 
Name inside block: NSNoName <0x103ae34c0> 
Changed name: NSNoFame <0x103ae3520> 

로그를 보면이 블록은 원래 소유 self.name 객체는 둘 다 동일한 메모리 주소를가집니다. viewController가 더 이상이 객체를 소유하지 않지만 self.name = "NSNoFame"을 변경하면 블록은 여전히 ​​객체의 동일한 인스턴스를 유지합니다.

신속성과 객관성의 차이는 ObjectiveC 블록이 전달 된 개체의 원본 인스턴스를 유지하면서 신속 폐쇄가 원래 인스턴스 변수의 복사본을 생성한다는 점입니다.

+0

이것은 빠른 코드 인 것 같습니다. OP는 ObjC에 대해 묻습니다. –

+0

@JoshCaswell 많이 다르지는 않지만 Objective C 블록으로 결론에 도달했습니다. – Sandeep

3

약한 참조는 보유 수를 늘리지 않으며 약한 참조는 단순히 객체에 대한 포인터이며 객체가 더 이상 존재하지 않으면 약한 속성이 nil로 설정되고 ARC가이를 처리합니다. 나는 블록 안에있는 약한 참조에 의해 객체의 개수가 증가한다고 생각하지 않는다.

약한 참조가 참조하는 인스턴스를 강력하게 유지하지 못하기 때문에 약한 참조가 계속 참조하는 동안 해당 인스턴스가 할당 취소 될 수 있습니다.따라서 참조하는 인스턴스가 할당 해제되면 ARC는 약한 참조를 nil로 자동 설정합니다.

문서 링크 : https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

ARC 귀하의 질문에 큰 도움이되지 못했습니다 내가 사과에서 이걸 발견 블록, 작동 방법에 대한 지금까지와 같은 특정 정보를 : https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

그러나,이 단락은 블록이 로컬 변수를 유지하는 방법을 이해하는 데 도움이 될 수 있습니다.

블록을 다른 언어의 클로저라고합니다 Python, Ruby 및 Lisp과 같이 선언 할 때 상태를 캡슐화하기 때문입니다. 블록은 범위 내부에서 참조되는 모든 로컬 변수의 const 복사본을 만듭니다.

에서 : http://www.raywenderlich.com/9438/how-to-use-blocks-in-ios-5-tutorial-part-2