2014-01-20 56 views
2

我对的NSString类别:线程安全

- (CGSize) agb_sizeWithFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode { 
    if (!font) return CGSizeZero; 

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 
    paragraphStyle.lineBreakMode = lineBreakMode; 
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil]; 

    // this line is not threadsafe 
    NSAttributedString *as = [[NSAttributedString alloc] initWithString:self attributes:attributes]; 

    CGRect bounds = [as boundingRectWithSize:CGSizeMake(width, 10000) options:(NSStringDrawingUsesLineFragmentOrigin) context:nil]; 
    return CGSizeMake(width, bounds.size.height); 
} 

我(在boundingRectWithSize:options:context:initWithString: attributes:有时,有时)上运行的多个线程的代码时观察到的间歇EXC_BAD_ACCESS崩溃。

我相信我的代码不是线程安全的,因为self可能会在一个线程上释放,而initWithString: attributes:正在另一个线程上执行。

  1. 我对这种方法的线程安全性的结论是否正确?
  2. 此代码是否会使其线程安全?

    NSString *strongSelf = self; 
    NSAttributedString *as = [[NSAttributedString alloc] initWithString:strongSelf attributes:attributes]; 
    

    (通过维持到self参考,我试图确保在内存中的对象,而我用它不释放。)

  3. 有什么办法来声明这种方法不线程安全?例如,如果声明为nonatomic属性的字符串被传入此方法,我希望生成警告。

注意:如果不明显,我使用ARC。

+1

是否启用ARC?使用ARC时,对象在执行其方法时不会被释放 –

+0

@BryanChen是,启用ARC。你确定这是类别方法吗? –

+3

从类别和其他方法声明的线程方法之间绝对没有区别。 –

回答

5

你的代码看起来像启用ARC,所以我认为它启用。

当initWithString:attributes:正在执行另一个线程时,self可能会释放一个线程。

这是不可能的ARC,因为为了执行agb_sizeWithFont...方法,你必须做这样的

NSString *str = /*...*/; // this will create a strong reference to str 
[str agb_sizeWithFont:/*...*/]; // even str is released in other thread at this point, it won't be deallocated 

NSString *strongSelf = self; 
东西

这个代码只需创建一个额外的强引用self ,但由于self必须保留在某个地方,它不会改变任何东西

我不认为你可以声明任何东西都是“不是线程安全的”(实际上所有的东西默认都不是线程安全的),我不明白你想如何使用这样的警告。


方法类别无明显差异比较法在@implementation关于线程安全。

+0

感谢您的澄清。你知道任何有关线程安全的类别方法没有什么不同的文档吗?你能想到我描述的任何其他可能的原因吗? –

+0

虽然我不知道有任何文档提及它...你能展示你的方法是如何使用的吗?它在多个线程中共享字符串?它是'NSMutableString'吗?你是否也启用NSZombie? –

+0

它是NSString,而不是NSMutableString。它用于计算后台线程的大小;这个大小添加到一些其他大小,缓存,并在稍后在'[UITableViewDelegate -heightForRowAtIndexPath:]'中使用。 –

6

任何NSMutableString is-a NSString。因此,您在NSString中添加的任何方法都可以在NSMutableString上调用。如果可能在另一个线程上同时发生变异,则在一个线程上对可变字符串进行操作是不安全的。 读取时,可以安全地读取另一个线程上的可变字符串。

由于您调用-[NSAttributedString initWithString:attributes:]正在从字符串self中读取,如果self是可变字符串,并且可能在同一时间在另一个线程上进行变异,则不安全。

您可能会想要检查-agb_sizeWithFont:width:lineBreakMode:的所有呼叫,以查看接收方的类型是否为NSMutableString*。然而,这还不够。 NSMutableString的一个实例可能由NSString*类型的变量(或其他类似NSObject*id)的变量指向。

您将无法使-agb_sizeWithFont:width:lineBreakMode:线程安全,因此。线程安全不会分解。它必须被设计成代码来管理它可能被调用的任何字符串。也就是说,所有接触给定字符串对象并可能调用你的方法的代码,在其他地方,可能会改变它,必须负责确保一次只有其中一件事发生。