2009-02-09 4 views
12

나는 코딩에 익숙하지 않고 Objective-C에 익숙해 지려고 노력하고있다. 내가 이해하지 못하는 일부 코드가 있습니다. 나는 누군가가 나를 위해 그것을 명확히하기를 바랄 수 있었다. 아래의 경우, foo2가 어떻게 작동하는지, 그리고 왜 풀리지 않는지 잘 모르겠습니다.Objective-C 포인터?

ClassOne *pointer = [[ClassOne alloc]init]; 

ClassTwo *foo = [[ClassTwo alloc]init], *foo2; 

foo2 = [foo add: pointer]; 
[foo release]; 
foo = foo2 

[pointer release]; 

[foo release]; 
+0

해당 클래스의 클래스 이름은 무엇입니까? –

+2

덧붙여 말하자면, 코드를 익명으로 처리하는 과정에서 이러한 문제가 발생했는지 알 수는 없지만 코드가 7 줄 밖에 안된다는 점을 감안할 때 상당히 혼란 스럽습니다. – Chuck

답변

1

아직 출시하지 않았기 때문에. 포인터를 해제하지 않고 여기서 참조 자료를 제공합니다. 그것은 똑같은 것이 아닙니다. [foo release]를 두 번째로 수행하면 foo2에 foo를 할당 할 때 생성 한 foo 참조가 해제됩니다.

foo2 참조를 해제하려면 참조 사본이 아니라 해당 참조에서 실제로 release를 호출해야합니다.

3
ClassOne *pointer = [[ClassOne alloc]init]; 

변수 pointer은 ClassOne 클래스의 객체에 대한 포인터입니다. 그것은 새로 생성 된 객체의 값을 할당합니다.

ClassTwo *foo = [[ClassTwo alloc]init], *foo2; 

*foo*foo2 클래스 ClassTwo의 개체입니다. 새롭게 생성 된 객체는 foo에만 할당됩니다. foo2은 아무 것도 가리킬 수 없으므로 값을 할당하기 전에 사용하는 것이 안전하지 않습니다.

foo2 = [foo add: pointer]; 

foo2에는 값이 할당된다 : I 클래스 ClassTwoadd: 메시지 오브젝트 목적은 foo 가리키는

[foo release]; 

아니요 (-(ClassTwo*)add:(ClassOne*);가 없어야있어서의 서명)을 생성한다고 가정 더 이상 필요합니다. 동일한 개체 모두 점 :

foo = foo2; 

가변 foofoo2의 값이 할당된다.

[pointer release]; 

pointer이 가리키는 개체는 더 이상 필요하지 않습니다.

[foo release]; 

목적은 foo (도 foo2에 의해) 더 이상 필요에 의해 지적했다.

+0

사실, 메소드의 서명은 - (ClassTwo *) add : (ClassOne *);이어야합니다. - 그/그녀의 예에서 수신자는 클래스 자체가 아니라 ClassTwo의 인스턴스입니다. –

+0

네, 맞습니다! 내 대답을 업데이트합니다. 고마워요. – mouviciel

1

간단한 예를 통해 무슨 일이 일어나고 있는지 말하기 란 정말 어렵습니다. 일반적으로 [class add :] 유형의 메소드는 void를 리턴하므로 'void 값은 무시하지 않아야한다'는 컴파일러 경고를 발생시켜야합니다.

더 많은 정보가 없으므로 문제를 파악하기가 약간 어렵습니다. 명심해야 할

몇 가지 :

  • 당신이 objc에서 '전무'에 명령을 보낼 수 있습니다. 따라서 [foo add : pointer]가 nil을 반환하면 하루 종일 영향을 미치지 않고 'release'를 호출 할 수 있습니다.

  • retainCount는 친구입니다. 모든 NSObject에서이 객체를 호출하여 보유하고있는 객체의 수를 확인할 수 있습니다. 또한 문제를 추적하는 데 도움이 될 수 있습니다.

  • 마지막으로 Garbage Collection on?

1

실제로는 [foo add:pointer];에 따라 다릅니다. 사본foo이고이를 유지하는 것으로 보입니다. 반환 된 객체가 복사/참조인지 여부는 메서드에서 분명해야하므로 분명히 잘못된 디자인입니다. add:이라는 메소드는 사본을 돌려주지 않습니다. 단계별로

단계 : 당신이 정말로 집중하려고 무엇

// this somehow creates a retained copy of foo. 
foo2 = [foo add:pointer]; 

// foo is released and gets destroyed. 
[foo release]; 

// makes foo point to the same object as foo2 
// (`foo` has no connection to the former object anymore) 
foo = foo2; 

// foo (and foo2 as they point to the same object) are released 
[foo release]; 
22

Objective-C Cocoa를 사용하여 반자동 참조 카운팅 메모리 관리 작업을하고 있습니다. 객체에 메모리를 할당하거나 객체를 보유하거나 객체에 copy 메소드를 호출하면 보유 수 (참조 횟수)가 1 씩 증가합니다. 객체에 release을 호출하면 보유 수를 1 씩 감소시킵니다. 객체에 autorelease을 호출하면 앞으로 어떤 시점에서 객체에 대해 release이 호출됩니다 (기본 실행 루프 중에는 자신의 코드가 실행되지 않을 때 참조로 인해 참조가 풀링되지 않습니다. 그것을 사용하려고 시도하고있다). 보유 수가 0에 도달하면 오브젝트를 할당 해제 할 수 있습니다. 당신이 객체에 retain를 호출하는 경우 일반적으로

는, 당신은에 관심을 신호하고, 당신은 객체에 더 이상 관심이 없을 때 당신은 어떤 점에서 release 또는 autorelease 통화를 할 책임이 있습니다 . 마찬가지로 개체에 alloc 또는 copy 메서드를 호출하면 해당 개체에 대한 관심이 표명되고 그 선의 아래 어딘가에 또는 autorelease과 일치해야합니다.

이 링크를 꽤 많이 지침 애플의 용도를 커버 (당신은 사용해야합니다) 메모리 관리 :

ClassOne *pointer = [[ClassOne alloc]init]; 

pointer 포인트 : Simple rules for memory management in Cocoa

가의 라인에 의해 코드 라인을 통해 가자 새로 할당 된 ClassOne 객체에 retain count가 1인데, alloc을 호출 한 이후입니다. 앞으로 release 또는 autorelease 번으로 pointer으로 전화해야 할 의무가 있습니다. 우리가에 ALLOC라고 이후 1의 유지 카운트

새로 할당 ClassTwo 객체에
ClassTwo *foo = [[ClassTwo alloc]init], *foo2; 

foo 점. 앞으로 release 또는 autorelease으로 전화하여 foo에 연락해야 할 의무가 있습니다.

foo2은 특히 현재 아무 것도 가리 키지 않습니다. 사용하는 것은 안전하지 않습니다.

pointer

foo2 = [foo add: pointer]; 

은 (그것이 의미하는 무엇이든 우리가 구현을 모르는) foo에 추가되었습니다. foopointerretain을 호출하여 해당 관심을 알리고 필드로 추가하거나 컬렉션에 pointer을 추가했을 수 있습니다.이 경우 개체가 추가 될 때 retain을 호출하는 것은 컬렉션의 책임입니다. 객체가 제거 될 때 release). 어쨌든 코드 블록에는 영향을 미치지 않으므로 코드 블럭에 아무런 영향을 미치지 않습니다.

이 메서드에서 반환하는 참조는 pointer 일 수도 있고 pointer의 자동 변환 된 복사본 일 수도 있습니다. 우리는 API 또는 구현에 액세스 할 필요가 없으므로이를 알려줍니다.

두 경우 모두 release에게 전화하는 것은 당사의 책임이 아닙니다. 메소드에 이름에 copy이 있거나 반환 된 참조 (예 : foo2 = [[foo add:pointer] retain];)에 retain을 호출 한 경우 보유 수는 1 씩 증가했으며 release 또는 autorelease을 호출하는 것은 Google의 책임이었습니다. foo 참조하는 오브젝트가 공개되어

[foo release]; 

은 그것의 카운트가 예를 들면 1만큼 감소 된 유지 즉, 우리는 라인 (2)에서 만든 alloc 호출이 쌍 때문에 카운트를 유지 0으로 떨어 지므로 foo이 해제 될 수 있습니다.

일반적으로 개체가 할당 취소되었는지 여부는 신경 쓰지 않습니다. alloc, copy 또는 retain 번의 전화 번호가 release 또는 autorelease과 같은 번호와 일치하는지 확인해야합니다. 우리가 언제든지 객체에 관심을 등록하면 우리의 관심을 해제하는 것이 우리의 책임입니다. 그렇지 않으면 메모리 누수가 발생합니다.

foo

foo = foo2; 

지금 foo2에 의해 참조 동일한 개체를 가리 킵니다. 우리가 foo2을 얻었을 때 alloc 또는 copy 메소드를 호출하지 않았으며 retain을 호출하여 관심을 등록하지 않았 음을 기억하십시오. releasefoo2으로 전화 할 의무가 없으므로 releasefoo으로 전화 할 의무가 없습니다.
[pointer release]; 

pointer '는의 1.이에 의해 감소 ​​된 수를 유지

0으로 그것의 유지 수를 가져왔다 수 있습니다 여부, 우리가 그것을 추가 할 때 그것으로 무엇을했는지 foo에 따라 달라집니다. 여전히 우리는 상관하지 않습니다. 우리는 처음에 만든 alloc 전화와 일치하도록 release을 호출하여 pointer에 대한 책임을 완료했습니다. 이 호출 후에도 pointer이 여전히있을지라도, 우리는 그 가정을 할 수 없으며, 이전에 포인터에 의해 참조 된 객체로 무엇을하려해도 실수가 될 수 있습니다. ( pointer을 자유롭게 변경할 수는 있지만).이 코드의 저자는 애플의 메모리 관리 규칙을 다음 한 경우

[foo release]; 

은, 다음이 필요하지 않습니다. 우리는 releasefoo 또는 foo2에 전화 할 책임이 없습니다 (그들은 같은 물체를 가리 킵니다. 기억하십시오). 이렇게하면 코드가 손상되지 않습니다. nil 참조 서에있는 어떤 것도 호출하는 것은 본질적으로 아무 작업도하지 않습니다. 그러나 코드를 검토하는 사람은 혼란을 야기 할 수 있습니다.

이제이 코드의 작성자가 메모리 관리 규칙을 위반했을 수 있습니다. 그는 add 호출을 autorelease으로 호출하지 않고 pointer 사본을 반환 할 수 있습니다.이 경우 호출자는 release을 호출해야합니다. 이것은 매우 나쁜 형식이며, 메모리 관리 규칙을 위반하는 코드를 실행해야하는 경우 사용하는 위치와 향후 혼란을 피하기 위해 규칙을 위반하는 방법을 문서화하십시오.

+3

메모리 관리 지침을 따르고 있다면 마지막에 [foo release]가 * 충돌 * 할 것입니다. 그것은 [foo add : pointer]의 결과로 설정됩니다. 우리는 이것이 모름이라는 것을 모릅니다. 그것이 nil 이외의 것이라면, 프로그램은 호황을 누립니다. – Chuck

1

와우, 대단히 감사합니다.

내가 실제로 의도 한 것은 객체가 아닌 포인터에 대한 참조입니다. 그럼에도 불구하고 나는 덧붙인 , *foo2이 foo와 같은 메모리에 있다고 추측한다. 또한 foo2는 foo와 동시에 메모리 형태로 해제됩니다. 나는 아직도 한 번에 하루를 기대고 더 많은 것을 가지고있다!