copy、weak、retain、assign、strong的实

2019-01-19  本文已影响136人  耿杰

0、主要解决以下几个问题

1、新建WTPerson的类

WTPerson.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface WTPerson : NSObject

@property (nonatomic, strong) NSMutableArray *strongArray;

@property (nonatomic, copy) NSMutableArray *cpyArray;

@property (nonatomic, assign) NSUInteger assignObj;

@property (nonatomic, weak) id idObj;

@property (nonatomic, retain) NSObject *retainObj;

- (void)initVar;

@end

NS_ASSUME_NONNULL_END

WTPerson.m

#import "WTPerson.h"

@implementation WTPerson
- (void)initVar
{
    self.strongArray = [NSMutableArray array];
    self.cpyArray = [NSMutableArray array];
    self.assignObj = 10;
    self.idObj = (id)[[NSObject alloc] init];
    self.retainObj = [[NSObject alloc] init];
}
@end

2、在相对应项目路径中,以下命令编译成对应的WTPerson.cpp文件

WTPerson.cpp

shell命令

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 WTPerson.m

3、WTPerson.cpp文件的源代码,找出成员变量的Setter函数的实现

image.png
1、strongassignweak
2、copyretain
3、所有修饰字的getter方法的实现都是通过(char *)self + OBJC_IVAR_$_WTPerson$_xxxx) , 如案例中strongArray,就是通过(char *)self + OBJC_IVAR_$_WTPerson$_strongArray),就是通过结构体WTPerson内存地址加上strongArray的偏移量,来获取对应内存地址的值。

4、测试atomicnonatomic开启6条线程,for循环10000次,各自时间是多少

测试代码

- (void)test
{
    TICK;
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.name = @"张三1";
            self.name;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        TOCK;
    });
    
    
}

结论:通过以下结果,使用atomic时间确实相对长一点,使用nonatomic时间相对短一点。按照以上文章所写,理论上atomic、strong是不加锁的,为什么使用时间长呢?希望有热心网友评论一下

12.481426 @property (atomic, copy) NSString *name;
11.998869 @property (atomic, copy) NSString *name;
12.355589 @property (atomic, copy) NSString *name;

1.999961 @property (nonatomic, copy) NSString *name;
2.019006 @property (nonatomic, copy) NSString *name;
2.015141 @property (nonatomic, copy) NSString *name;

7.278346  @property (atomic, strong) NSString *name;
6.806363  @property (atomic, strong) NSString *name;
6.928921  @property (atomic, strong) NSString *name;

0.425550 @property (nonatomic, strong) NSString *name;
0.442165 @property (nonatomic, strong) NSString *name;
0.547891 @property (nonatomic, strong) NSString *name;

20190120 更新

1、运行时分析

1、对name进行赋值

测试代码

@property (nonatomic, strong) NSString *name;
- (void)test
{
    self.name = @"张三1";  
}
2、开启汇编调试模式
image.png
3、单步进入
image.png
4、发现setName内部其实是调用了objc_setProperty_nonatomic函数
image.png
5、objc_setProperty_nonatomic内部还是调用reallySetProperty函数,第四个参数是false,表明是被nonatomic修饰的,所以最终不会加锁。当然这个是objc4源码中所得,根据之前的经验,说明objc4源码只有参考意义,具体测试还是得运行时查看
image.png
6、打上断点,进入objc_setProperty_nonatomic函数内部
image.png
7、在控制台输入si,表明进入这个函数内部
image.png
8、继续回车,表示继承执行si命令
image.png
9、一直回车到dyld_stub_binder
image.png
10、在dyld_stub_binder,最后一行打上断点,并跳过
image.png
11、再一次回车进入objc_setProperty_atomic
image.png
12、可以发现确实是利用os_unfair_lock进行加锁的
image.png
13、分别测试了
objc_setProperty_atomic
objc_setProperty_atomic_copy
objc_setProperty_nonatomic_copy
objc_setProperty_nonatomic
objc_setProperty_atomic
objc_storeWeak
objc_storeWeak
没有其他方法
没有其他方法

2、weak

1、 、使用了weak修饰词,发现最终调用了objc_storeWeak,内部其实是调用storeWeak函数,没有发现类似atomic的参数,下面进入storeWeak函数看实现
objc_storeWeak

2、发现函数实现,无条件地加了锁。所以猜测使用weak修饰字的属性,无论是使用nonatomicatomic,都是加了锁的

加锁 解锁

3、测试了一下代码结果

通过以下结果, 得出的结论就是使用weak修饰字的属性,无论是使用nonatomicatomic,都是加了锁的

// 代码执行时间
#define TICK   NSDate *startTime = [NSDate date];
#define TOCK   NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
- (void)test
{
    
    TICK;
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.idObj = nil;
            self.idObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        TOCK;
    });
    
    
}

结果

7.224174 @property (atomic, weak) id idObj;
7.078933 @property (atomic, weak) id idObj;
6.948409 @property (atomic, weak) id idObj;

7.192473 @property (nonatomic, weak) id idObj;
7.071997 @property (nonatomic, weak) id idObj;
7.238427 @property (nonatomic, weak) id idObj;
4、发现SideTable的锁,是spinlock_t, 也就是os_unfair_lock
image.png
image.png
5、跟踪汇编汇编代码查看, 不停地si,进入setObj函数内部
image.png
6、再次不停地si、进入objc_storeWeak函数内部
image.png
7、翻阅整个汇编流程,发现内部还是调用了os_unfair_lock进行加锁
image.png

3、assign

1、测试结果表明,得出的结论就是使用assign修饰字的属性,无论是使用nonatomicatomic,都不会加锁的

测试代码

// 代码执行时间
#define TICK   NSDate *startTime = [NSDate date];
#define TOCK   NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
- (void)test
{
    
    TICK;
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_group_enter(group);
        for (NSUInteger i = 0; i < 10000000;  i++)
        {
            self.assignObj = 10;
            self.assignObj;
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        TOCK;
    });
    
    
}

结果

1.434344 @property (atomic, assign) NSUInteger assignObj;
1.561307 @property (atomic, assign) NSUInteger assignObj;
1.420304 @property (atomic, assign) NSUInteger assignObj;

1.112815 @property (nonatomic, weak) id idObj;
1.116036 @property (nonatomic, weak) id idObj;
1.458600 @property (nonatomic, weak) id idObj;
2、从运行时分析,汇编看不太懂,但是基本可以看出直接赋值的,具体等我学习汇编,再来更新
运行时

结论

上一篇 下一篇

猜你喜欢

热点阅读