source

ARC에서 항상 자신의 약한 참조를 블록에 전달하시겠습니까?

nicesource 2023. 4. 9. 21:43
반응형

ARC에서 항상 자신의 약한 참조를 블록에 전달하시겠습니까?

Objective-C에서의 블록 사용에 대해 조금 혼란스럽습니다.나는 현재 ARC를 사용하고 있고 내 앱에는 꽤 많은 블록이 있으며, 현재 항상 다음을 참조하고 있다.self참조가 약한 대신.그것이 이러한 블록이 유지되는 원인일 수 있습니다.self할당 해제되는 것을 막을 수 있을까요?문제는, 제가 항상 VIP를 사용해야 한다는 것입니다.weak에 대한 언급.self블록에?

-(void)handleNewerData:(NSArray *)arr
{
    ProcessOperation *operation =
    [[ProcessOperation alloc] initWithDataToProcess:arr
                                         completion:^(NSMutableArray *rows) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateFeed:arr rows:rows];
        });
    }];
    [dataProcessQueue addOperation:operation];
}

Process Operation.h

@interface ProcessOperation : NSOperation
{
    NSMutableArray *dataArr;
    NSMutableArray *rowHeightsArr;
    void (^callback)(NSMutableArray *rows);
}

Process Operation.m

-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{

    if(self =[super init]){
        dataArr = [NSMutableArray arrayWithArray:data];
        rowHeightsArr = [NSMutableArray new];
        callback = cb;
    }
    return self;
}

- (void)main {
    @autoreleasepool {
        ...
        callback(rowHeightsArr);
    }
}

집중하지 않는 것이 도움이 됩니다.strong또는weak논의의 일부입니다.대신 사이클 파트에 초점을 맞춥니다.

유지 사이클은 객체A가 객체B를 유지하고 객체B가 객체A를 유지할 때 발생하는 루프입니다.이 상황에서 어느 하나의 오브젝트가 해방된 경우:

  • 오브젝트 B가 오브젝트에 대한 참조를 보유하고 있기 때문에 오브젝트 A는 할당 해제되지 않습니다.
  • 그러나 오브젝트 A에 참조가 있는 한 오브젝트 B는 할당 해제되지 않습니다.
  • 그러나 오브젝트 A는 오브젝트 B에 대한 참조가 있기 때문에 할당 해제되지 않습니다.
  • 애드 인피니텀

따라서 이 두 개체는 모든 것이 제대로 작동한다면 할당 해제되어야 하지만 프로그램의 수명 동안 메모리에 남아 있게 됩니다.

즉, 유지 사이클이 우려됩니다.블록 자체만으로는 이러한 사이클이 발생하지 않습니다.이것은 문제가 되지 않습니다.예를 들어 다음과 같습니다.

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

블록이 유지되다self,그렇지만self블록은 유지되지 않습니다.둘 중 하나가 릴리스되면 사이클이 생성되지 않고 모든 것이 정상적으로 할당 해제됩니다.

문제가 되는 것은 다음과 같습니다.

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [self doSomethingWithObj:obj];     
}];

이제, 당신의 목적(self)에는 명시적인 내용이 있습니다.strong블록에 대한 참조.그리고 이 블록은 암묵적으로 강한 참조를 가지고 있습니다.self이 주기는 주기이며, 이제 어느 개체도 제대로 할당 해제되지 않습니다.

왜냐하면, 이런 상황에서는self 정의상 이미 가 있다strong블록에 대한 참조는 일반적으로 명시적으로 약한 참조를 함으로써 가장 쉽게 해결할 수 있습니다.self사용할 블록:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

, 이것은 호출하는 블록을 처리할 때 따르는 기본 패턴은 아닙니다.self! 이것은 자기와 블록 사이의 유지 사이클을 깨기 위해서만 사용해야 합니다.이 패턴을 모든 곳에 적용한다면 블록이 전달될 위험이 있습니다.self을 사용하다

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not retained!
  [weakSelf doSomething];
}];

@jemmons에 전적으로 동의합니다.

그러나 이것이 셀프라고 불리는 블록을 처리할 때 따르는 기본 패턴은 아니어야 합니다.이것은 자기와 블록 사이의 유지 사이클을 깨는 데에만 사용해야 합니다.이 패턴을 모든 곳에 적용한다면, 자기 배정이 해제된 후에 실행되는 무언가에 블록을 전달하는 위험을 감수해야 합니다.

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not  retained!
  [weakSelf doSomething];
}];

하려면 , 이 강한 할 수 .weakSelf록록: :

__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  MyObject *strongSelf = weakSelf;
  [strongSelf doSomething];
}];

항상 약한 참조를 사용할 필요는 없습니다.블록이 유지되지 않고 실행된 후 폐기된 경우 유지 사이클이 생성되지 않으므로 자신을 강하게 캡처할 수 있습니다.경우에 따라서는 블록이 완료될 때까지 블록이 자체 상태를 유지하여 너무 빨리 할당 해제되지 않도록 할 수도 있습니다.그러나 블록을 강하게 캡처하고 내부 캡처 셀프일 경우 유지 사이클이 생성됩니다.

Leo가 지적한 바와 같이, 질문에 추가한 코드는 강한 참조 주기(예: 유지 주기)를 시사하지 않습니다.강력한 참조 사이클을 일으킬 수 있는 동작 관련 문제 중 하나는 동작이 해제되지 않는 경우입니다.에 의해,되어 있지 않은 것이 행해지고 있는 는, 「」를 투고하지 는 릴리스 isFinished.조작이 해제되지 않으면 뷰 컨트롤러도 해제되지 않습니다.이나 중단점을 하는 것이 .NSLog ★★★★★★★★★★★★★★★★★★★★★★★★★.dealloc이치노

당신이 말했다:

유지 사이클의 개념은 이해하지만 블록에서 무슨 일이 일어나는지 잘 모르기 때문에 조금 혼란스럽습니다.

블록에서 발생하는 유지 주기(강력한 참조 주기) 문제는 익숙한 유지 주기 문제와 동일합니다.블록은 블록 내에 표시되는 개체에 대한 강력한 참조를 유지하고 블록 자체가 해제될 때까지 이러한 강력한 참조를 해제하지 않습니다. references의 self 단순히 인 ''를 self는 자신에은 블록이 이 「」가 해제될 까지) 되지 않습니다.NSOperation서브클래스가 해방됩니다.

자세한 내용은 Programming with Objective-C: Working with Blocks 문서의 "Self Capting self(셀프 캡처 시 강력한 참조 주기 방지)" 섹션을 참조하십시오.

경우 되지 않은 하는 위치를 (「」를 합니다).NSOperation할당 해제됩니다).로 '하다'를 들 수 .NSTimer 커스텀도 delegate strong하여 할 수 예를 다음과 같습니다.계측기를 사용하여 개체가 강력한 참조를 얻는 위치를 추적할 수 있습니다. §:

Xcode 6에서의 참조 카운트 기록

또는 Xcode 5의 경우:

Xcode 5에서의 참조 카운트 기록

일부 설명에서는 보유 사이클에 관한 조건을 무시합니다(강력한 관계의 원에서 오브젝트 그룹이 연결되어 있는 경우 그룹 외부에서 강력한 참조가 없어도 서로 존속합니다).상세한 것에 대하여는, 문서를 참조해 주세요.

블록 내부의 Self를 사용할 수 있는 방법은 다음과 같습니다.

//블록의 개요

 NSString *returnedText= checkIfOutsideMethodIsCalled(self);

NSString* (^checkIfOutsideMethodIsCalled)(*)=^NSString*(id obj)
{
             [obj MethodNameYouWantToCall]; // this is how it will call the object 
            return @"Called";


};

언급URL : https://stackoverflow.com/questions/20030873/always-pass-weak-reference-of-self-into-block-in-arc

반응형