strong修饰符潜在问题及解决办法
- 潜在问题:在多线程环境下,如果多个线程同时对一个strong修饰的属性进行赋值操作,可能会导致内存管理问题,比如对象被意外提前释放或过度释放。因为每个线程都可能认为自己是最后一个持有对象的线程从而释放它。另外,读写操作如果没有同步,可能会读到未完成赋值的“脏数据”。
- 示例代码:
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *myString;
@end
@implementation MyClass
@end
// 多线程操作
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
MyClass *obj = [[MyClass alloc] init];
dispatch_async(queue1, ^{
for (int i = 0; i < 1000; i++) {
obj.myString = [NSString stringWithFormat:@"Value from queue1 - %d", i];
}
});
dispatch_async(queue2, ^{
for (int i = 0; i < 1000; i++) {
obj.myString = [NSString stringWithFormat:@"Value from queue2 - %d", i];
}
});
- 解决办法:可以使用锁(如
@synchronized
、dispatch_semaphore
等)来同步对该属性的访问。
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *myString;
@property (nonatomic, strong) id lock;
@end
@implementation MyClass
- (instancetype)init {
self = [super init];
if (self) {
self.lock = [[NSObject alloc] init];
}
return self;
}
- (void)setMyString:(NSString *)myString {
@synchronized(self.lock) {
_myString = myString;
}
}
- (NSString *)myString {
@synchronized(self.lock) {
return _myString;
}
}
@end
weak修饰符潜在问题及解决办法
- 潜在问题:weak修饰的属性本身不会增加对象的引用计数,在多线程环境下,一个对象可能在某线程中被释放,而其他线程中还持有该weak指针。当访问这个已释放对象的weak指针时,会得到nil,可能导致程序逻辑错误,例如在期望对象存在并执行方法时发生崩溃。
- 示例代码:
@interface ParentClass : NSObject
@property (nonatomic, strong) ChildClass *child;
@end
@implementation ParentClass
@end
@interface ChildClass : NSObject
@end
@implementation ChildClass
@end
// 多线程操作
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
ParentClass *parent = [[ParentClass alloc] init];
dispatch_async(queue1, ^{
parent.child = [[ChildClass alloc] init];
// 模拟一些操作
[NSThread sleepForTimeInterval:1];
parent.child = nil;
});
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:0.5];
ChildClass *weakChild = parent.child;
// 这里weakChild可能已经是nil,如果继续操作可能崩溃
[weakChild doSomeMethod];
});
- 解决办法:在使用weak指针前,需要进行非空判断,确保对象存在。
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:0.5];
ChildClass *weakChild = parent.child;
if (weakChild) {
[weakChild doSomeMethod];
}
});
copy修饰符潜在问题及解决办法
- 潜在问题:在多线程环境下,多个线程同时对copy修饰的属性进行赋值操作,可能会导致性能问题,因为每次赋值都需要进行一次拷贝操作。而且如果拷贝操作没有同步,可能会导致数据不一致。
- 示例代码:
@interface MyClass : NSObject
@property (nonatomic, copy) NSString *myCopyString;
@end
@implementation MyClass
@end
// 多线程操作
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
MyClass *obj = [[MyClass alloc] init];
dispatch_async(queue1, ^{
for (int i = 0; i < 1000; i++) {
obj.myCopyString = [NSString stringWithFormat:@"Value from queue1 - %d", i];
}
});
dispatch_async(queue2, ^{
for (int i = 0; i < 1000; i++) {
obj.myCopyString = [NSString stringWithFormat:@"Value from queue2 - %d", i];
}
});
- 解决办法:同样可以使用锁来同步对该属性的访问,减少不必要的拷贝操作,同时保证数据一致性。
@interface MyClass : NSObject
@property (nonatomic, copy) NSString *myCopyString;
@property (nonatomic, strong) id lock;
@end
@implementation MyClass
- (instancetype)init {
self = [super init];
if (self) {
self.lock = [[NSObject alloc] init];
}
return self;
}
- (void)setMyCopyString:(NSString *)myCopyString {
@synchronized(self.lock) {
_myCopyString = myCopyString;
}
}
- (NSString *)myCopyString {
@synchronized(self.lock) {
return _myCopyString;
}
}
@end