programing

이 블록에서 자신을 강하게 포착하는 것은 유지 사이클로 이어질 수 있다

elseif 2023. 4. 19. 22:27

이 블록에서 자신을 강하게 포착하는 것은 유지 사이클로 이어질 수 있다

이 경고를 xcode로 회피하려면 어떻게 해야 합니까?코드 스니펫은 다음과 같습니다.

[player(AVPlayer object) addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil usingBlock:^(CMTime time) {
    current+=1;

    if(current==60)
    {
        min+=(current/60);
        current = 0;
    }

    [timerDisp(UILabel) setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];///warning occurs in this line
}];

「 」의 self여기 당신의 암묵적인 재산 접근과 함께 들어옵니다.self.timerDisp안 요. - 이렇게 하면 안 돼요.self 는는의 self에 의해 강하게 유지되는 블록 내에서self.

를 피하려면 , 보다 .self 액세스 전에timerDisp「 」:

__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
                                     queue:nil
                                usingBlock:^(CMTime time) {
                                                current+=1;

                                                if(current==60)
                                                {
                                                    min+=(current/60);
                                                    current = 0;
                                                }

                                                 [weakSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];
                                            }];
__weak MyClass *self_ = self; // that's enough
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
    if (!error) {
       [self_ showAlertWithError:error];
    } else {
       self_.items = [NSArray arrayWithArray:receivedItems];
       [self_.tableView reloadData];
    }
};

그리고 한 가지 매우 중요한 점은 인스턴스 변수를 블록에서 직접 사용하지 말고 취약한 개체의 속성으로 사용한다는 것입니다. 샘플:

self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
        if (!error) {
           [self_ showAlertWithError:error];
        } else {
           self_.items = [NSArray arrayWithArray:receivedItems];
           [_tableView reloadData]; // BAD! IT ALSO WILL BRING YOU TO RETAIN LOOP
        }
 };

잊지 말고 다음 작업을 수행합니다.

- (void)dealloc {
    self.loadingCompletionHandler = NULL;
}

anyone object에 의해 유지되지 않은 약한 복사본을 전달하면 다음과 같은 다른 문제가 발생할 수 있습니다.

MyViewController *vcToGo = [[MyViewCOntroller alloc] init];
__weak MyViewController *vcToGo_ = vcToGo;
self.loadingCompletion = ^{
    [vcToGo_ doSomePrecessing];
};

vcToGo이되지 않는 셀렉터와 함께 하며, 이 셀렉터는 에 크래쉬합니다.인식되지 않는 셀렉터와 크래쉬를 하면 다음 항목이 포함된 휴지통으로 이동합니다.vcToGo_이제 변수입니다.조절해 보세요.

더 나은 버전

__strong typeof(self) strongSelf = weakSelf;

블록의 첫 번째 행으로서 그 약한 버전에 대한 강한 참조를 작성합니다.블록이 실행되기 시작해도 self가 계속 존재하며 0이 되지 않으면 이 행은 블록의 실행 수명 동안 지속됩니다.

그래서 모든 것은 이렇게 될 것이다.

// Establish the weak self reference
__weak typeof(self) weakSelf = self;

[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
                                 queue:nil
                            usingBlock:^(CMTime time) {

    // Establish the strong self reference
    __strong typeof(self) strongSelf = weakSelf;

    if (strongSelf) {
        [strongSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];
    } else {
        // self doesn't exist
    }
}];

나는 이 기사를 여러 번 읽었다.블록NSNotification Center 사용 시 문제를 피하는 방법에 대한 Erica Sadun훌륭한 기사입니다.


빠른 업데이트:

예를 들어 success block을 사용하는 간단한 방법은 다음과 같습니다.

func doSomeThingWithSuccessBlock(success: () -> ()) {
    success()
}

self성공 블록에 있습니다.및 기능을 사용합니다.

    doSomeThingWithSuccessBlock { [weak self] () -> () in
        guard let strongSelf = self else { return }
        strongSelf.gridCollectionView.reloadData()
    }

소위 강약무용이라고 불리는 이 춤은 인기 있는 오픈 소스 프로젝트에서 사용됩니다.

자세한 내용은 swift-style-guide를 참조하십시오.

또 다른 답변에서 Tim은 다음과 같이 말했다.

자기 자신에 의해 강하게 유지되는 블록 안에서 자기 자신이나 자신의 속성을 언급할 수 없습니다.

이것은 완전히 사실이 아니다.어느 시점에서 사이클을 끊는 한 이 작업은 괜찮습니다.예를 들어, 자신을 유지하는 블록이 있는 타이머가 기동하고, 그 타이머에 대한 강한 참조를 스스로 유지하고 있다고 합니다.어느 시점에서 타이머가 파괴되어 사이클이 중단되는 것을 항상 알고 있으면, 이것은 문제 없습니다.

방금 전의 경우, 다음과 같은 코드에 대해 경고를 받았습니다.

[x setY:^{ [x doSomething]; }];

이제 우연히 알게 된 것은 clang이 메서드가 "set"로 시작하는 것을 감지했을 때에만 이 경고가 발생한다는 것입니다(그리고 여기서 언급하지 않을 다른 특별한 경우도 있습니다).저는 유지 루프가 발생할 위험이 없다는 것을 알고 있기 때문에 메서드 이름을 "useY:"로 변경했습니다.물론 모든 경우에 적절하지는 않을 수 있으며, 보통은 약한 참조를 사용하고 싶을 것입니다만, 다른 사람에게 도움이 될 수 있는 경우는, 제 솔루션에 주의할 필요가 있다고 생각했습니다.

많은 경우, 이것은 실제로 유지 사이클이 아닙니다.

만약 그렇지 않다는 걸 안다면, 결실없는 나약한 자신을 세상에 내놓을 필요는 없어.

은 API를 .UIPageViewController여기에는 블록인 ivar에 값을 설정하고 있다고 생각되는 설정 방법(다른 곳에서 설명한 바와 같이 이러한 경고를 트리거함)과 완료 핸들러 블록(의심 없이 자신을 참조할 수 있음)이 포함됩니다.

다음은 해당 코드 한 줄에서 경고를 삭제하라는 컴파일러 지시입니다.

#pragma GCC diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
    [self.pageViewController setViewControllers:@[newViewController] direction:navigationDirection animated:YES completion:^(BOOL finished) {
        // this warning is caused because "setViewControllers" starts with "set…", it's not a problem
        [self doTheThingsIGottaDo:finished touchThePuppetHead:YES];
    }];
#pragma GCC diagnostic pop

정밀도와 스타일을 향상시키는 데 2센트를 더한다., 은 한 명 두 명 는 한 명 두 입니다.self이 블록에서는 슬라이더만 업데이트 할 수 있습니다. ★★★★self과잉 살상이야대신, 블록 내에 정말로 필요한 객체만 캐스팅하고 명시적인 것이 좋습니다.예를 들어, 이 인스턴스가UISlider*를 들면, , 말,,,,,,,._timeSlider에 다음

UISlider* __weak slider = _timeSlider;

그냥 쓰세요.slider, 을 필요한 , 내부에 있는 오브젝트가 필요한 오브젝트만으로 에, 보다 합니다.self.

완전한 예:

UISlider* __weak slider = _timeSlider;
[_embeddedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1)
     queue:nil
     usingBlock:^(CMTime time){
        slider.value = time.value/time.timescale;
     }
];

약한 안쪽의 .self또한 유지 주기의 가능성을 최소화하거나 완전히 제거합니다.에서는 " " " 입니다._timeSlider는 실제로 약한 참조로 저장된 속성입니다. §:

@property (nonatomic, weak) IBOutlet UISlider* timeSlider;

코딩 스타일에 관해서는 C 및 C++와 마찬가지로 변수 선언을 오른쪽에서 왼쪽으로 읽는 것이 좋습니다.SomeType* __weak variable으로 보다 variable is a weak pointer to SomeType.

최근에 우연히 이 경고를 받았고 좀 더 잘 이해하고 싶었습니다.약간의 시행착오를 거친 후, 저는 이것이 "추가" 또는 "저장"으로 시작하는 메서드에서 비롯되었다는 것을 발견했습니다.목표 C는 "new", "alloc" 등으로 시작하는 메서드 이름을 보존 개체를 반환하는 것으로 처리하지만 "add" 또는 "save"에 대해서는 언급하지 않습니다.단, 메서드 이름을 다음과 같이 사용하는 경우:

[self addItemWithCompletionBlock:^(NSError *error) {
            [self done]; }];

경고는 줄에 표시해 두겠습니다.단, 이것은 다음과 같이 되지 않습니다.

[self itemWithCompletionBlock:^(NSError *error) {
    [self done]; }];

'_weak_typeof(self) weakSelf = self' 방식을 사용하여 내 대상을 참조하지만 미래의 나 및/또는 다른 개발을 혼란스럽게 하기 때문에 그렇게 해야 하는 것은 정말 싫다.물론 "추가" (또는 "저장")도 사용할 수 없지만, 이는 메서드의 의미를 빼앗기 때문에 더 심각합니다.

언급URL : https://stackoverflow.com/questions/14556605/capturing-self-strongly-in-this-block-is-likely-to-lead-to-a-retain-cycle