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;
}
다른 사람이 보유하지 않은 약한 사본을 전달하면 다른 문제가 발생할 수 있습니다.
MyViewController *vcToGo = [[MyViewCOntroller alloc] init];
__weak MyViewController *vcToGo_ = vcToGo;
self.loadingCompletion = ^{
[vcToGo_ doSomePrecessing];
};
경우 vcToGo
해제 한 후이 블록 해고 될 것입니다 당신이 포함되어있는 휴지통으로 인식 할 수없는 선택기 충돌을 얻을 것으로 예상 vcToGo_
이제 변수를. 그것을 제어하십시오.
답변
더 나은 버전
__strong typeof(self) strongSelf = weakSelf;
블록의 첫 번째 줄로 약한 버전에 대한 강력한 참조를 작성하십시오. 블록이 실행을 시작하고 nil로 다시 떨어지지 않았을 때 self가 여전히 존재한다면,이 행은 블록의 실행 수명 동안 계속 유지되도록합니다.
따라서 모든 것이 다음과 같습니다.
// 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
}
}];
이 기사를 여러 번 읽었습니다. Erica Sadun의 블록 및 NSNotificationCenter 사용시 문제를 피하는 방법 에
대한 훌륭한 기사입니다.
신속한 업데이트 :
예를 들어, 신속하게 성공 블록을 사용하는 간단한 방법은 다음과 같습니다.
func doSomeThingWithSuccessBlock(success: () -> ()) {
success()
}
이 메소드를 호출 self
하고 성공 블록에서 사용해야 할 때 . [weak self]
및 guard let
기능을 사용하겠습니다 .
doSomeThingWithSuccessBlock { [weak self] () -> () in
guard let strongSelf = self else { return }
strongSelf.gridCollectionView.reloadData()
}
이 소위 강약 댄스는 인기있는 오픈 소스 프로젝트에서 사용됩니다. Alamofire
.
자세한 내용은 신속한 스타일 가이드를 확인하십시오.
답변
다른 대답으로, Tim은 다음과 같이 말했습니다.
자체적으로 강력하게 유지되는 블록 내에서 자체 또는 자체 속성을 참조 할 수 없습니다.
이것은 사실이 아닙니다. 어떤 시점에서 사이클을 중단하지 않는 한이 작업을 수행해도됩니다. 예를 들어, 자체를 유지하는 블록이있는 타이머가 작동하고 자체적으로 타이머에 대한 강력한 참조를 유지한다고 가정 해 봅시다. 어떤 시점에서 타이머를 파괴하고 사이클을 중단한다는 것을 항상 알고 있다면 이것은 완벽하게 좋습니다.
제 경우에는 다음과 같은 코드에 대한 경고 메시지가 나타납니다.
[x setY:^{ [x doSomething]; }];
이제 clang이 메소드가 “set”(및 여기서 언급하지 않은 다른 특별한 경우)으로 시작하는 것을 감지하면이 경고 만 생성한다는 것을 알게되었습니다. 나에게, 유지 루프가있을 위험이 없다는 것을 알고 있으므로 메서드 이름을 “useY”로 변경했습니다. 물론 모든 경우에 적합하지 않을 수 있으며 일반적으로 약한 참조를 사용하려고합니다. 다른 사람들을 도울 수 있도록 내 솔루션을 주목할 가치가 있다고 생각했습니다.
답변
여러 번, 이것은 실제로 유지주기가 아닙니다 .
그렇지 않다는 것을 알면 과일이없는 약한 자아를 세상에 가져올 필요가 없습니다.
Apple은 API를 사용하여 이러한 경고를 강제로 수행합니다 UIPageViewController
. 여기에는 set 메소드 (다른 곳에서 언급했듯이 경고를 트리거하여 블록 인 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
.
답변
나는 최근에이 경고에 부딪 쳤고 그것을 조금 더 이해하고 싶었다. 약간의 시행 착오 끝에, 메소드가 “add”또는 “save”로 시작하는 것에서 비롯된 것을 발견했습니다. Objective C는 “new”, “alloc”등으로 시작하는 메소드 이름을 보유 된 오브젝트를 리턴하는 것으로 취급하지만 “add”또는 “save”에 대해서는 언급하지 않습니다. 그러나이 방법으로 메소드 이름을 사용하면 :
[self addItemWithCompletionBlock:^(NSError *error) {
[self done]; }];
[self done] 행에 경고가 표시됩니다. 그러나 이것은 :
[self itemWithCompletionBlock:^(NSError *error) {
[self done]; }];
계속해서 “__weak __typeof (self) weakSelf = self”방식을 사용하여 내 객체를 참조하지만 실제로는 미래의 나 및 / 또는 다른 개발자를 혼동시키기 때문에 그렇게하는 것을 좋아하지 않습니다. 물론 “add”(또는 “save”)도 사용할 수 없지만 방법의 의미를 없애기 때문에 더 나쁩니다.