문제

한동안 블록을 사용해 왔지만 ARC 환경과 비 ARC 환경 모두에서 메모리 관리에 대해 놓치는 부분이 있다는 것을 느낍니다.나는 더 깊은 이해를 통해 많은 메모리 누수를 피할 수 있을 것이라고 생각합니다.

AFNetworking은 특정 애플리케이션에서 블록을 주로 사용하는 것입니다.대부분의 경우 작업 완료 핸들러 내에서 "[self.myArray addObject]"와 같은 작업을 수행합니다.

ARC 및 비 ARC 지원 환경 모두에서 "자체"는 다음에 따라 유지됩니다. 이 기사는 Apple에서 나왔습니다..

즉, AFNetworking 네트워크 작업의 완료 블록이 호출될 때마다 self는 해당 블록 내에 유지되고 해당 블록이 범위를 벗어나면 해제됩니다.나는 이것이 ARC와 비ARC 모두에 적용된다고 생각합니다.메모리 누수를 찾기 위해 Leaks 도구와 정적 분석기를 모두 실행했습니다.아무도 보여주지 않았습니다.

그러나 최근까지 제가 이해할 수 없는 경고를 우연히 발견한 것은 아니었습니다.이 특정 예에서는 ARC를 사용하고 있습니다.

네트워크 작업의 완료 및 실패를 나타내는 두 개의 인스턴스 변수가 있습니다.

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;

코드 어딘가에서 다음을 수행합니다.

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
                                                    responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
            _failureBlock(error);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"nothing");
        }];

Xcode는 failureBlock을 호출하는 줄에 대해 "이 블록에서 "self"를 강력하게 캡처하면 유지 주기가 발생할 가능성이 높다는 메시지와 함께 불평합니다.나는 Xcode가 옳다고 생각합니다.실패한 블록은 자체를 유지하고 자체는 자체 블록 복사본을 보유하므로 둘 중 어느 것도 할당 해제되지 않습니다.

그러나 다음과 같은 질문/관찰이 있습니다.

1) _failureBlock(error)을 "self.failureBlock(error)"(따옴표 제외)로 변경하면 컴파일러가 불평을 멈춥니다.왜 그런 겁니까?이것은 컴파일러가 놓친 메모리 누수인가요?

2) 일반적으로 다음을 사용할 때 ARC 및 비 ARC 지원 환경 모두에서 블록 작업을 수행하는 가장 좋은 방법은 무엇입니까? 인스턴스 변수인 블록?AFNetworking에서 완료 및 실패 블록의 경우 이 두 블록은 다음과 같습니다. ~ 아니다 인스턴스 변수를 사용하므로 위에서 설명한 유지 주기 범주에 속하지 않을 수 있습니다.그러나 AFNetworking에 진행 블록을 사용할 때 위와 같은 유지 주기를 방지하려면 어떻게 해야 할까요?

블록이 포함된 ARC 및 비ARC에 대한 다른 사람들의 생각과 메모리 관리 관련 문제/해결책을 듣고 싶습니다.나는 이러한 상황이 오류가 발생하기 쉽다고 생각하며 문제를 해결하기 위해 이에 대한 논의가 필요하다고 생각합니다.

중요한지는 모르겠지만 최신 LLVM과 함께 Xcode 4.4를 사용합니다.

도움이 되었습니까?

해결책

1) _FailureBlock (오류)을 "self.failureblock (오류)"로 변경하면 (따옴표없이) 컴파일러가 불평을 멈추게합니다. 왜 그런 겁니까? 이것이 있습니다 컴파일러가 누락 된 메모리가 누락 되었습니까?

두 경우 모두 유지 사이클이 존재합니다. iOS 5+를 타겟팅하는 경우, 자체에 대한 약한 참조를 전달할 수 있습니다.

__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
    if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"nothing");
}];
.

이제 자체는 유지되지 않으며 콜백이 호출되기 전에 할당 해제하면 콜백은 NO-OP입니다. 그러나 콜백이 백그라운드 스레드에서 호출되는 동안 할당 해제 할 수 있으므로이 패턴이 가끔 충돌을 만들 수 있습니다.

2) 일반적으로 두 가지 모두에서 블록을 사용하는 것이 가장 좋은 방법은 무엇입니까? 아크 및 아크 비 아크 사용 가능 환경 인스턴스 변수? 완료 및 실패의 경우 Afnetworking의 블록,이 두 블록은 인스턴스 변수가 아닙니다. 그들은 아마도 내가 보유주기의 범주에 빠지지 않을 것입니다. 전술 한 바와. 그러나 진행률 블록을 Afnetworking으로 사용할 때, 위의 것과 같은 순환을 피하기 위해 수행 할 수있는 것은 무엇입니까?

대부분의 시간은 이게 더 좋지 않습니다. 인스턴스 변수의 블록을 저장합니다. . 대신 클래스의 메서드에서 블록을 반환하면 여전히 유지 사이클이 있지만 블록이 해제되는 시간에 메서드가 호출되는 시간부터 만 발생합니다. 따라서 블록 실행 중에 인스턴스가 할당 해제되지 않지만 블록이 릴리스 될 때 유지 사이클이 종료됩니다.

-(SFCompletionBlock)completionBlock {
    return ^(AFHTTPRequestOperation *operation , id responseObject ) {
        [self doSomethingWithOperation:operation];
    };
}

[self.operation setCompletionBlockWithSuccess:[self completionBlock]
                                      failure:[self failureBlock]
];
.

다른 팁

즉, Afnetworking 네트워크 작동의 완료 블록이 호출 될 때마다 해당 블록 내부에 자체가 유지되고 해당 블록이 범위를 벗어날 때 해제됩니다.

아니요, self 블록이 생성될 때 블록에 의해 유지됩니다.그리고 블록이 할당 해제되면 해제됩니다.

나는 Xcode가 옳다고 생각합니다.실패 블록은 자체를 유지하고 자체는 자체 블록 사본을 보유하므로 두 가지 중 어느 것도 거래되지 않습니다.

문제의 블록이 유지됩니다. self 전달된 완료 블록은 다음과 같습니다. setCompletionBlockWithSuccess. self 이 블록에 대한 참조를 보유하지 않습니다.꽤, self.operation (아마도 일종의 NSOperation)는 실행되는 동안 블록을 유지합니다.그래서 일시적인 사이클이 있습니다.그러나 작업 실행이 완료되면 주기가 중단됩니다.

1) _failureBlock (error)을 "self.failureBlock (error)"으로 변경하면 컴파일러가 불만을 중지합니다.왜 그런 겁니까?이것은 컴파일러가 누출되면 메모리가 누출됩니까?

차이가 없어야 합니다. self 두 경우 모두에서 캡처됩니다.컴파일러는 유지 주기의 모든 경우를 포착한다고 보장하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top