@synchronized在MRC中不起作用,我的应用程序在多线程中崩溃

时间:2014-09-16 02:19:14

标签: ios multithreading automatic-ref-counting synchronized

//person.h
@interface Person : NSObject

@property(retain, nonatomic) NSString *indexStr;

- (instancetype)initWithIndex:(int)index;

- (void)print;

@end

//person.m
@implementation Person

- (instancetype)initWithIndex:(int)index
{
    if (self = [super init]) {
        _indexStr = [NSString stringWithFormat:@"%d",index];
        NSLog(@"person init index:%d",index);
    }
    return self;
}

- (void)dealloc
{
    self.indexStr = nil;
    NSLog(@"person dealloc index:%@",self.indexStr);
    [super dealloc];
}

@end    

//vc.h
@property (retain, nonatomic) Person *person;

//vc.m
- (void)viewDidLoad {
    [super viewDidLoad];

    _person = [[Person alloc] initWithIndex:-1];

    for (int i = 0; i < 100000; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self actionWrite:@(i)];
        });
    }

    //    [NSThread detachNewThreadSelector:@selector(actionRead) toTarget:self withObject:nil];
}

- (void)actionWrite:(NSNumber *)num
{
    @synchronized(self) {
        self.person = [[[Person alloc] initWithIndex:[num intValue]] autorelease];
    }
}

代码在MRC中。

它会在&#34; actionWrith:&#34;崩溃方法。日志是:

2014-09-16 10:11:26.452 testThreadNoARC[1777:149948] person init index:357
2014-09-16 10:11:26.452 testThreadNoARC[1777:149961] person init index:358
2014-09-16 10:11:26.452 testThreadNoARC[1777:149947] person init index:359
2014-09-16 10:11:26.452 testThreadNoARC[1777:149937] person init index:360
2014-09-16 10:11:26.452 testThreadNoARC[1777:149944] person init index:361
2014-09-16 10:11:26.452 testThreadNoARC[1777:149950] person init index:362
2014-09-16 10:11:26.452 testThreadNoARC[1777:149941] person init index:363
2014-09-16 10:11:26.452 testThreadNoARC[1777:149959] person init index:364
2014-09-16 10:11:26.452 testThreadNoARC[1777:149955] person init index:365
2014-09-16 10:11:26.452 testThreadNoARC[1777:149951] person init index:366
2014-09-16 10:11:26.452 testThreadNoARC[1777:149958] person init index:367
2014-09-16 10:11:26.466 testThreadNoARC[1777:149975] person init index:368
2014-09-16 10:11:26.466 testThreadNoARC[1777:149964] person init index:369
2014-09-16 10:11:26.466 testThreadNoARC[1777:149971] person init index:370
2014-09-16 10:11:26.466 testThreadNoARC[1777:149863] *** -[CFString release]: message sent to deallocated instance 0x7fdc5bec77b0

每次都在主题1中崩溃,我不知道为什么会这样快乐。 我认为Person对象已经被释放,可能会再次释放以进行崩溃。 但每次我运行代码时,它的崩溃日志都是一样的。 相同的代码在ARC上运行良好。

2 个答案:

答案 0 :(得分:0)

您没有保留用于_indexStr的字符串。变化:

_indexStr = [NSString stringWithFormat:@"%d",index];

为:

_indexStr = [[NSString stringWithFormat:@"%d",index] retain];

答案 1 :(得分:0)

您的Person初始化程序中包含以下行:

    _indexStr = [NSString stringWithFormat:@"%d",index];

stringWithFormat:消息返回自动释放的值。您将它直接存储到由retain属性管理的实例变量中。由于您绕过了setter,因此setter没有机会保留它。一旦自动释放池耗尽,该字符串将被释放。由于您从未保留过它,系统会将其解除分配。现在_indexStr是一个悬空指针。

稍后,在-[Person dealloc]中,您执行此操作:

self.indexStr = nil;

由于indexStrretain属性,因此其setter如下所示:

- (void)setIndexStr:(NSString *)value {
    NSString *oldValue = _indexStr;
    [value retain];
    _indexStr = value;
    [oldValue release];
}

这意味着当setter执行[oldValue release]时,它会将release发送到该悬空指针。这是你崩溃的地方。

最好的办法是停止使用MRC 开始使用ARC

在MRC下,您可以通过多种方式在Person初始值设定项中正确保留字符串。其中任何一个都可以:

    _indexStr = [[NSString stringWithFormat:@"%d",index] retain];

    // or

    self.indexStr = [NSString stringWithFormat:@"%d",index]

    // or

    _indexStr = [[NSString alloc] initWithFormat:@"%d", index];