2012-06-20 3 views
0

문맥에 대한 블록 함수와 값을 테스트하고 싶습니다. 테스트 코드는 다음블록 함수 및 메모리 문제가있는 개체 -c

//xxx.h

@interface textObj : NSObject 
@property (nonatomic, retain) NSNumber * num; 
@end 

typedef void (^ returnHandle)(NSNumber * res); 

@interface BlockTest : NSObject 

- (void) textBlock:(textObj *)num completionHandler:(void (^)(NSNumber * res))handler; 

@end 

//xxx.m

@implementation textObj 
@synthesize num; 

@end 

@interface BlockTest(){ 
    returnHandle rt; 
} 

- (void)toggleChromeDisplay; 

@end 

@implementation BlockTest 

- (void) dealloc{ 
    Block_release(rt); 
    [super dealloc]; 
} 

- (void)toggleChromeDisplay 
{ 
    NSNumber *ret = [NSNumber numberWithInt:111]; 
    rt(ret); 
} 

void (^handle)(NSNumber * res, NSError *error); 


- (void) textBlock:(textObj *)g1 completionHandler:(void (^)(NSNumber * res))handler 
{ 
    rt = Block_copy(handler); 
    [self performSelector:@selector(toggleChromeDisplay) withObject:nil afterDelay:0.5]; 
    return; 
} 

@end 

시험 샘플 호출 코드 : 블록의

//first sample code... 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    test = [[BlockTest alloc]init]; 
    textObj * g1; 
    g1 = [[textObj alloc] init]; 
    [g1 setNum:[NSNumber numberWithInt:10]]; 
    NSLog(@"main 0 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    [test textBlock:g1 completionHandler:^(NSNumber *res) { 
     NSLog(@"value=%@", [g1 num]); 
     [g1 setNum:[NSNumber numberWithInt:20]]; 
     NSLog(@"main 1 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    } ]; 
    NSLog(@"main 2 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    [g1 release]; 
    NSLog(@"main 3 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
} 

함수, 나는 g1 값을 변경할 수 있습니다. 괜찮아. 그러나 g1을 테스트의 공개 값으로 선언하면 블록 함수에서 오류가 발생합니다. g1은 액세스 할 수 없습니다. EXC_BAD_ACCESS (코드 = 2, 주소 = 0x26) 오류을 출력합니다. 나는 두 개의 서로 다른 sampe 코드를 혼동입니다

//second sample code... 
@interface UIMainViewController(){ 
@public 
    textObj * g1; 
} 
@end 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    test = [[BlockTest alloc]init]; 
    //textObj * g1; 
    g1 = [[textObj alloc] init]; 
    [g1 setNum:[NSNumber numberWithInt:10]]; 
    NSLog(@"main 0 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    [test textBlock:g1 completionHandler:^(NSNumber *res) { 
     NSLog(@"value=%@", [g1 num]); 
     [g1 setNum:[NSNumber numberWithInt:20]]; 
     NSLog(@"main 1 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    } ]; 
    NSLog(@"main 2 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
    [g1 release]; 
    NSLog(@"main 3 g1 num=%@ count=%d", [g1 num], [g1 retainCount]); 
} 

, 왜 두 번째 테스트 코드는 충돌을 충족?

+0

"오류가 발생합니다"- 오류는 무엇입니까? –

+0

은 g1 값에 액세스 할 수 없습니다. EXC_BAD_ACCESS 오류가 출력됩니다. – Golden

+0

물론 그렇습니다 ...'[g1 release]'후에, g1이 할당 해제되므로 2 차 NSLog가 실제로 그 일을 많이 할 수는 없습니다 ... –

답변

1

@ H2CO3은 블록이 실행되기 전에 g1을 릴리스한다고 설명합니다. 한 경우에만 작동하고 다른쪽에 작동하지 않는 이유는 blocks retain any local object variables they refer to when copied입니다.

첫 번째 예에서 g1은 메소드 범위의 로컬 변수이므로 블록이이를 유지합니다.

두 번째 예에서 g1은 ivar (사실 self->g1)이므로 블록은 self을 유지합니다. 그러나 블록을 선언 한 직후 g1을 릴리스하므로 self->g1을 호출하면 g1이 할당 취소되었으므로 잘못된 포인터가 반환됩니다.

+0

도움 주셔서 감사합니다. ivar g1 (self-> g1)의 경우, 수명은 컨테이너 자체와 동일해야합니다. 이 ivar은 init 함수에서 할당하고 dealloc 함수에서 해제해야합니다. – Golden

+0

하지만 첫 번째 예는 g1이 실제로 출시 될 때입니까? 블록이 끝나거나 컨테이너가 스스로 풀린 후? 나는 첫 번째 예와 두 번째 예에서 기억의 것을 분명히하고 싶다. – Golden

+0

첫 번째 예에서 블록이 할당 해제되면 g1이 할당 해제됩니다. 콜백의 경우 일반적으로 블록을 실행 한 후에 해제해야합니다. –

3

retainCount는 쓸모가 없습니다. 전화하지 마세요. 절대로.

정의에 따르면 retainCount는 0을 반환 할 수 없습니다. 할당되지 않은 객체를 메시징하고 ​​있습니다.이 객체는 정의되지 않았으며 종종 충돌하는 동작을합니다.