2012-06-20 37 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)錯誤

//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]); 
} 

我混淆了兩個不同的sampe代碼,爲什麼第二個測試代碼會碰到crash?

+0

「It will error」 - 錯誤是什麼? – 2012-06-20 08:36:59

+0

無法訪問值g1。將輸出EXC_BAD_ACCESS錯誤。 – Golden

+0

當然它確實...在'[g1發佈]'之後,g1被重新分配,所以第二個NSLog無法真正做到這一點...... – 2012-06-20 09:03:15

回答

1

主要的問題是,正如@ H2CO3所指出的那樣,在塊被執行之前,你會發布g1。它在一種情況下工作的原因是blocks retain any local object variables they refer to when copied

在第一個示例中,g1是方法作用域的局部變量,所以塊保留它。

在你的第二個例子中,g1是伊娃(實際上是self->g1),所以該塊保留self。但是在聲明塊後立即釋放g1,所以當塊調用self->g1時,它會得到一個無效指針,因爲g1已被釋放。

+0

感謝您的幫助。對於伊娃g1(self> g1),壽命應與容器自身相同。這個ivar應該在init函數中進行分配,並在dealloc函數中釋放。 – Golden

+0

但是對於第一個例子,當g1會真的釋放?塊完成或容器自行釋放後?我想清楚他的第一個例子和第二個例子之間的記憶。 – Golden

+0

在第一個示例中,當塊被釋放時,g1將被釋放。對於回調,通常應該在運行後釋放該塊。 –

3

retainCount沒用。別叫它。永遠不會。

根據定義,retainCount不能返回零。你正在傳遞一個未定義的釋放對象,通常是崩潰的行爲。