이것은 많은 의견을 갖고 있으며 "Objective-C에서 메모리 관리가 작동하는 방식에 대한 지식이 심하게 부족하다는 것을 확인한 답변이 적절합니다"라고 말한 적이 있지만 특정 오류를 지적한 사람은 아무도 없습니다. 나는 그 (것)들에 만진 대답을 추가 할 것입니다.
, 우리 생성 된 객체의 소유권을 갖는다. ¹ 우리가 물건의 소유권을 가지고 있다면, 우리는 그것을 풀어주는 책임이 있습니다.
이라는 메서드 호출에이 포함되어 있지 않으면 생성 된 개체의 소유권이 없습니다. ¹ 에 개체의 소유권이없는 경우이를 공개하는 것은 이 아니며 우리의 책임이므로 결코 수행해서는 안됩니다.
는의 각 줄에 영업 이익의 코드를 살펴 보자 : -(UIImage *) downloadImageToFile {
우리는 새로운 방법을 시작했다. 이렇게함으로써 우리는 생성 된 각 객체가 살아있는 새로운 맥락을 시작했습니다. 이것을 명심하십시오.다음 라인 : NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];
우리는 url
소유 : 단어 ALLOC는 우리는 개체의 소유권을 가지고 우리는 그것을 자신을 해제해야합니다 것을 우리가 알 수 있습니다. 코드가 없으면 메모리가 누수됩니다. 네 개의 마법의 단어 더 사용, 그래서 우리는 소유권을 가지고 있지 않고, 그것을 자신을 해제해서는 안 :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
우리는 paths
를 소유하지 않습니다. 마법의 단어 = 소유권 :
NSString *documentsDirectory = [paths objectAtIndex:0];
우리는 documentsDirectory
를 소유하지 않습니다.
[paths release]
다시 우리가 경로를 보유하고 있지 않습니다 것을 볼 줄 몇가는, 그래서 우리는 더 이상 존재하지 않는 무언가를 액세스하려고으로이 릴리스는 EXC_BAD_ACCESS 충돌의 원인이됩니다. 마법의 단어 = 소유권 : NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];
우리는 path
를 소유하지 않습니다.
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
우리는 data
소유 : 단어를 ALLOC를이 우리가 개체의 소유권을 가지고 사용을 지시하고 우리가 그것을 자신을 해제 할 필요가있다. 코드가 없으면 메모리가 누수됩니다.
다음 두 줄은 아무것도 만들지 않거나 해제하지 않습니다. 그런 다음 마지막 줄이옵니다.
}
메서드가 끝났기 때문에 변수의 컨텍스트가 종료되었습니다. 코드를 살펴보면 우리는 url
과 data
을 모두 소유하고 있었지만 어느 쪽도 공개하지 않았다는 것을 알 수 있습니다. 따라서이 메서드가 호출 될 때마다 코드에서 메모리가 누수됩니다.
NSURL
개체 url
은 그리 크지 않기 때문에 누출을 알지 못할 수도 있습니다. 그래도 정리해야하지만 누출 될 이유는 없습니다.
NSData
개체 data
은 매우 큰 이미지 일 수 있습니다. 이 메서드가 호출 될 때마다 개체의 전체 크기가 누출됩니다. 테이블 셀이 그려 질 때마다 이것이 호출되었다고 상상해보십시오 : 전체 앱을 충돌시키는 데 오랜 시간이 걸리지는 않습니다.
그렇다면 문제를 해결하기 위해 무엇을해야합니까? 바로 전에,
-(UIImage *) downloadImageToFile {
// We own this object due to the alloc
NSURL * url = [[NSURL alloc] initWithString: self.urlField.text];
// We don't own this object
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// We don't own this object
NSString *documentsDirectory = [paths objectAtIndex:0];
//[paths release] -- commented out, we don't own paths so can't release it
// We don't own this object
NSString * path = [documentsDirectory stringByAppendingString:@"/testimg.png"];
// We own this object due to the alloc
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
[url release]; //We're done with the url object so we can release it
[data writeToFile:path atomically:YES];
[data release]; //We're done with the data object so we can release it
return [[UIImage alloc] initWithContentsOfFile:path];
//We've released everything we owned so it's safe to leave the context
}
어떤 사람들은 한 번에 모든 것을 공개하는 것을 선호 : 그것은 우리가 단순히 그들이 사용하고 일반적으로 바로 마지막 시간 이후, 곧 우리가 더 이상 필요하지 않기 때문에 개체를 해제 할 필요가 꽤 간단합니다 컨텍스트는 메소드의 끝에서 닫힙니다. 이 경우 [url release];
및 [data release];
은 닫는 }
중괄호 바로 앞에 나타납니다. 코드를 더 빨리 공개하면 코드가 명확 해 지므로 나중에 오브젝트를 사용하여 완료 한 부분을 정확하게 볼 수 있습니다.
은 요약하면 : 우리는 상황이 종료되기 전에 그래서 그들을 해제해야 호출 방법에 alloc
, new
, copy
, 또는 retain
로 만든 개체를 소유하고 있습니다. 우리는 다른 것을 소유하지 않으며 절대 공개해서는 안됩니다. 네 개의 단어에서 실제로 마법 거기에 아무것도
¹, 그들은 단지 문제의 방법을 만든 애플에서의 사람들에 의해 지속적으로 사용되는 알림입니다. 자체 클래스의 초기화 또는 복사 메서드를 만드는 경우 해당 메서드에 alloc, new, copy 또는 retain이라는 단어를 포함시키는 것은 우리의 책임이며 우리 이름에 사용하지 않으면 소유권이 지났는지를 스스로 기억할 필요가 있습니다.
링크를 제공해 주셔서 감사합니다. 내 실제 코드에서는 내가 명시 적으로 할당하지 않았을 때 경로를 해제하려고했는데 나중에 문제가 발생했습니다. 그리고 당신 말이 맞습니다. 저는 obj-c로 시작하고 있습니다. 그리고 나는 그것이 생각했던 것보다 훨씬 더 복잡합니다. – Kevlar
아무 문제도, 내가 너무 가혹한 소리하지 않았 으면 좋겠다. 그 문서는 읽을만한 가치가 있습니다. 당신의 개발에 행운을 비네! – August
최근에 EXC_BAD_ACCESS에 대한 많은 질문을 던지면서 디버깅 기술 목록과 함께 http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html에 설명해 드렸습니다. 이 경우 (릴리스가 너무 많음) Build and Analyze/scan-build가 아마 플래그를 지정했을 것입니다. 그렇지 않으면 좀비를 사용하면 분명히 가질 수 있습니다. –