계측기가 다음 방법에 대해보고하는 메모리 누수를 수정하기 위해 거의 뼈를 부러 뜨리고 있습니다.
- (BOOL)moveCloudFileToLocal: (NSString*)cloudFilePath error: (NSError**)error
{
// each variable starting with an underscore is an ivar
BOOL bSuccess = NO;
@autoreleasepool
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* docPathLocal = [paths objectAtIndex:0];
NSURL* sourceURL = [NSURL fileURLWithPath:cloudFilePath]; // => LEAKING!!!
NSString* destFileName = sourceURL.lastPathComponent;
NSURL* destFileURL = [[NSURL fileURLWithPath:docPathLocal]
URLByAppendingPathComponent:destFileName]; // => LEAKING!!!
NSArray* arrArgs = @[ sourceURL, destFileURL ]; // => LEAKING!!!
NSThread* thread = [[NSThread alloc] initWithTarget: self
selector: @selector(threadMoveCloudFileToLocal:)
object: arrArgs];
_threadCloud = thread;
[_threadCloud start];
}
[self waitForMovingThreadToFinish];
if (error != nil)
*error = _retError;
bSuccess = (_retError == nil);
return bSuccess;
}
Instruments는 arrArgs, sourceURL 및 destFileURL이 다음과 같이 루트 누출을 일으킨다 고 말합니다.
더 많은 정보는 Instruments의이 출력이지만 결과에 익숙하지 않으므로 누수를 해결하기 위해 어떤 조치를 취해야하는지 알 수 없습니다.
다음 세 가지 변수를 다르게 작성하려고 추가로 시도했습니다.
NSURL __autoreleasing* sourceURL...;
NSURL __autoreleasing* destFileURL...;
NSArray __autoreleasing* arrArgs...;
불행히도 이것은 아무것도 변경하지 않으며 동일한 방식으로 계속 누출됩니다. 좋아요, 그것은 충돌하지 않지만 누출되어 수리하고 싶습니다. iOS 7.0.3과 함께 iPhone Simulator를 사용하여 OS X 10.9.5에서 Xcode 6.1.1을 사용하고 있습니다.
여기에 힌트가 있습니까?
요청에 따라 편집, 추가 코드 부분 :
- (void)threadMoveCloudFileToLocal: (NSArray*)args
{
// args:
// 1: sourceURL = iCloud file
// 2: destFileURL = local file
//
_bgTaskExpired = NO;
@autoreleasepool
{
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{ self->_bgTaskExpired = YES; }];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if ([args count] != 2)
goto finished;
{
NSError* lastError = nil;
NSURL* sourceURL = [args objectAtIndex:0]; // sourceURL is the iCloud file
__block NSURL* destFileURL = [args objectAtIndex:1]; // destFileURL is the local file
__block NSError* theError = nil;
__block BOOL bSuccess = NO;
_retError = nil;
_fileCoord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
[_fileCoord coordinateWritingItemAtURL: sourceURL
options: NSFileCoordinatorWritingForDeleting
error: &lastError
byAccessor: ^(NSURL* newURL)
{
NSFileManager* fileManager = [[NSFileManager alloc] init];
if (AfxGetApp().numVersion >= 6.0)
{
bSuccess = [fileManager setUbiquitous:NO itemAtURL:newURL destinationURL:destFileURL error:&theError];
if (bSuccess)
{
theError = nil;
bSuccess = [fileManager evictUbiquitousItemAtURL:newURL error:&theError];
if (!bSuccess && [iCloudSupport errorIsFileNotFound:theError])
{
bSuccess = YES;
theError = nil;
}
}
}
else
{
// on iPad1 with iOS 5.1.1 it is hanging with the above procedure
//...code not being shared, not relevant
}
if (bSuccess)
[self removeFilePathFromContainers:sourceURL.path];
}];
_fileCoord = nil;
if (lastError == nil && theError != nil)
lastError = theError;
if (!bSuccess && lastError == nil)
lastError = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:nil];
_retError = lastError;
}
finished:
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
} // end @autoreleasepool
[NSThread exit];
}
- (void)waitForMovingThreadToFinish
{
while (_threadCloud && ![_threadCloud isFinished])
{
// Wait for the thread to finish.
[NSThread sleepForTimeInterval:0.1];
}
}
BTW : 정적 분석기는 내 코드에서 단일 경고가 아니라 아무것도 찾지 못합니다. 동적으로 실행될 때만 나타납니다. 코드는 iOS 6과 iOS 7이 막 나왔을 때의 것입니다. 그 당시 이전 SDK에서는 불만이 없었습니다. evictUbiquitousItemAtURL : 조차도 현재 문서에서와 같이 조정 된 쓰기와 함께 사용할 때 문서에서 교착 상태로 표시되지 않았습니다. iOS 5.1.1에서 실행 되었음에도 불구하고 교착 상태가 발생하지 않았기 때문에 별도의 조건부 else 부분이 있습니다.
편집 : 더 명확하게하기 위해 추가 악기 출력
몇 줄의 코드를 변경하기 전에 Instruments에서이 코드보기를 가져 왔습니다.
스레드 생성 문 내에서 객체로 전달되는 매개 변수 배열을 구축하기 위해 몇 줄의 코드를 변경 한 후에는 정확히 NSArray 인스턴스화 줄만 누수되기 때문에 Instruments에서 상당히 흥미로워 보입니다. 불행히도 나는 그 이유를 이해하지 못하고 그것을 고치는 방법을 모릅니다.
에 대한 호출을 제거해야합니다 [NSThread exit]
. 스레드의 루트 자동 해제 풀이 드레 이닝되는 것을 방지합니다.
+ (void) exit
말할 문서 :
이 메서드를 호출하면 스레드가 실행 중에 할당 한 리소스를 정리할 수있는 기회를주지 않으므로 피해야합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다