1

어떻게 removeFromSuperView가 정상적으로 작동합니까? 내가보기메모리 관리

- (id)init { 
    if (!(self = [super init])) 
     return nil; 

    _mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    UIButton *reInitButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f,0.0f,90.0f,35.0f)];  
    [reInitButton addTarget:self action:@selector(buttonDidTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 

    return self; 
} 

- (void)buttonDidTapped:(id)sender { 
    [_mainView removeFromSuperView]; //crash during second times press the button 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    _mainView = [[UIView alloc] initWithFrame[[UIScreen mainScreen] bounds]]; 
    [[self view] addSubView:_mainView]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
    [_mainView release]; 
    NSLog(@"retainCount :%d", [_mainView retainCount]); 
} 

을 REINIT 할 때 메모리 문제에게 나쁜 액세스를 가지고 내가 어떤 유지하거나 ALLOC 또는 키워드 해제가 모든 시간 NSLog 있습니다. 결과는 매우 이상합니다.

//init 
retainCount : 1 
retainCount : 2 
retainCount : 1 
//1st time pressed button 
retainCount : 1 //remove super view didn't decrease 
retainCount : 2 
retainCount : 1 
//2nd time pressed button 
retainCount : 0 //crash. Memory bad access 

이상한 일이 처음으로 눌려지지 않은 이유는 무엇입니까 ??

답변

3

내가 당신의 문제에 대해 생각 :

[_mainView release]; 

당신은 내 독서에 의해, 아직 _mainView에 대한 참조를 감소하고, 한, 그건 당신이 주위를 유지하고 메소드를 호출 계속하겠습니다 멤버 변수입니다 . 그건 유효하지 않아. -release을 호출하면 본질적으로 해당 개체를 다시 사용하지 않을 것이라고 말했고 -removeFromSuperView에 전화 할 때와 마찬가지로 해당 개체에 대한 부실 포인터와 관련된 유용한 작업을 수행 할 수 없습니다. 나중에 그것.

계속 _mainView을 유지하고 코드를 호출하려면 참조를 유지해야합니다. 아마도 릴리스를 객체의 -dealloc 메소드로 이동해야합니다. 또는 버튼 메서드에서 -release 수 있으며 다음에 필요할 때 새보기를 다시 만듭니다.

도움이되는 팁으로, 많은 프로그래머가 객체를 다시 사용한 후 다시 사용할 수 없다는 것을 알려주기 위해 객체를 해제 한 후 NULL (또는 objC에서 말하는 nil)으로 재설정하려고합니다. 만약 당신이 -release 뭔가, 당신은 그것을 의미하는 것이 좋습니다.

마지막으로 Google에 "참조 카운팅"이라는 용어를 제안하고 이에 대해 읽어보십시오. 그것은 NSObject의 세부 사항보다 더 일반적인 숙어이며, 기초를 생각하고 이것을 C와 같은 다른 언어로 구현하는 방법을 생각하는 것이 유용 할 것입니다. 이것은 참조 계산 된 객체에 대해 더 잘 추론하는 데 도움이 될 것입니다.

+0

+1이이 경우에는 nil로 설정됩니다. –

+0

릴리즈를'dealloc'으로 옮기고 버튼의 액션에서 새로운 뷰를 생성해도 누수가 발생합니다. –

+0

@ Josh Caswell - 네, 맞습니다. 이것은'nil'가 유용하게 쓰이는 곳입니다 ... if (_mainView) [_mainView release]; _mainView =/* ... * /;'아직 dealloc에 ​​릴리즈하고 싶습니다. – asveikau

3

다시 사용하지 말고을 사용하십시오. 대문자로 쓰는 것에 대해 유감스럽게 생각합니다. 그러나 사람들이 왜 그것을 사용하는지에 대한 내 인생을 이해할 수는 없습니다. 메모리 관리에 대한 잘못된 참조입니다. 악기 등을 대신 사용하십시오.

+0

ok 나는 그것을 더 이상 사용하지 않을 것이고, 문제는 무엇인가, 나는 그것이 필요할 때 언제든지 풀어 놓는다 고 생각하지만 여전히 충돌이다. buttonDidTapped에서 릴리스를 언급 한 경우 충돌이 발생하지 않았지만 누출되었다고 생각합니다. – Lunayo

+0

참조 횟수를 관찰하는 것은 좋지 않습니다 (참조 횟수가 "보유 횟수"보다 더 표준적인 용어이므로 Google에 대해 자세히 알아보십시오). '-retain' 또는'-release'와 같은 특정 메소드의 구현 외부. 문제는 refcount가 0이고 refcount 자체를 뒷받침하는 메모리를 포함하여 객체를 백업하는 메모리가 해제되므로 참조를 삭제 한 후 객체에 액세스하는 것이 안전하지 않은 것과 같은 이유입니다. 'free' 후 버퍼. 다른 코드도 기억을 유지하고 해제 할 수 있으며 자신의 행동에 의존 할 수 없습니다. – asveikau

+0

@ Lunayo : [retainCount는 유해한 것으로 간주됩니다] (http://stackoverflow.com/questions/5784084/) 주제에 대한 다른 흥미로운 읽기 : [1] (http://stackoverflow.com/questions/5155559/) [2] (http://stackoverflow.com/questions/5483357/) [3] (http://stackoverflow.com/questions/5391479/) [4] (http://stackoverflow.com/questions/3354724/) [5 ] (http://stackoverflow.com/questions/5220902/) –

2

그 시점에서 _mainView에 액세스하면 안됩니다. 설명하기가 어려울 수 있으므로 나와 함께 감내하십시오. 우리는 셀 수는 있지만 개체에 대한 코드의 클레임 수는 절대 보유하지 않습니다.

당신은 _mainView와의 객체 및 지점에 대한 메모리를 할당 :

_mainView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

당신은 해당 개체에 대한 소유 한 주장이있다. 다른보기의 하위보기로 추가하면 해당보기도 마찬가지로 소유권 주장을하지만 사용자의보기가 아니라보기입니다. _mainView 안에있는 물건을 주변에 붙이게한다는 사실은 사고이며, 당신은 그것에 의지해서는 안됩니다. 당신은 지금 0 주장을 가지고, 당신은 더 이상이 개체에 액세스하려고합니다 - 당신은 당신의 소유권 주장을 포기했다

[_mainView release]; 

: 그럼 당신은 객체를 해제하지 않습니다. 당신은 그것을 소유하지 않습니다.다시 한 번, 다른 뷰가 그것을 사용하고 있기 때문에 그것이 여전히 존재한다는 사실과 당신이 여전히 그것에 대한 포인터를 가지고 있다는 사실은 사고 *이며, 당신은 그것들에 의지해서는 안됩니다.

그것은 당신의 버튼을 누른을 처리 할 수있는 시간을 제공

후, 당신은 소유권이없는 이상 개체에 액세스 :

[_mainView removeFromSuperView]; 

이 기대되지 않을 수 있습니다 충돌, 원인, 그러나 그것은이다 부당하지 않다. 소유권 주장을 0으로하면 시스템에 "이 개체가 더 이상 필요하지 않으며이 시점 이후에 액세스하지 않을 것이며 사라지면 영향을받지 않을 것입니다."라고 말했습니다. 사실, 당신은 을 수행해야합니다.은 주변에 머물러 있어야하며, 액세스해야합니다. 바로 removeFromSuperview에 대한 호출 후, 버튼 액션 내부에

[_mainView release]; 

: 당신이 무엇을해야

는 다음 라인으로 이동합니다.


은 두 번째는이 경우, 출시 후 _mainView = nil;을 설정하여 피할 수 *,하지만 더 큰 문제가 해결되지 않습니다.