经常使用的属性修饰符有前端
atomic,nonatomic,strong,retain,weak,assign,unsafe_unretained,copy,readonly,readwritegit
copy
和strong
可变对象 copy是深拷贝程序员
不可变对象 copy是浅拷贝github
mutableCopy 始终是深拷贝数组
copy
修饰NSString/NSArray/NSDictory
由于使用copy来修饰不可变对象,能够保证安全安全
扩展:async
copy
浅拷贝 不拷贝对象自己,仅仅是拷贝指向对象的指针(复制的对象和原对象都指向同一个地址)函数
mutableCopy
深拷贝 直接拷贝整个对象内存到另外一块内存中ui
copy
去修饰NSMutableArray
会怎么样?使用copy
修饰可变数组以后,数组初始化的时候,会执行copy
方法,生成的是一个不可变的数组,当执行[arr addObject:]
时会crash
atom
atomic
原子性,不是绝对线性安全的
@property (atomic, assign) NSInteger intA; //有一个atomic的属性,表示是原子的 - (void)viewDidLoad { [super viewDidLoad]; //开启一个线程对intA的值+1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i = 0;i < 1000;i ++){ self.intA = self.intA + 1; } NSLog(@"intA : %ld",(long)self.intA); }); //开启一个线程对intA的值+1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i = 0;i < 1000;i ++){ self.intA = self.intA + 1; } NSLog(@"intA : %ld",(long)self.intA); }); }
错误分析:
由于intA
是atomic
修饰的,因此是线程安全的,在+1
的时候,只会有一个线程去操做,因此最终的打印结果一定有一个是2000
输出以下:
intA : 1186 intA : 896
分析:
其实atomic
是原子的是没问题的,这个只是表示set
方法是原子的,效果相似与下面的效果
//atomic表示的是对set方法加锁,表示在设置值的时候,只会有一个线程执行set方法 - (void)setIntA:(NSInteger)intA{ [self.lock lock]; _intA = intA; [self.lock unlock]; }
只是对set
方法加锁,而咱们代码里面的self.intA = self.intA + 1;
,这一部分不是线程安全的,正确的处理方法是:
[self.lock lock]; self.intA = self.intA + 1; [self.lock unlock];
一个程序至少有一个进程,一个进程至少有一个线程。同一个进程内的线程共享进程里的资源。
堆 由程序员分配释放,通常用来存放对象(ARC下会自动释放)
栈 由编译器自动分配释放,存放函数的参数值、局部变量的值等
UIButton
继承自什么?为何?UIButton
是一个能够响应事件的控件,所以它的直接父类是UIControl
,UIControl
的直接父类是UIView
。
UIButton
从父类UIControl
那继承了控制相关的方法,好比添加事件、移除事件等
UIResponder
响应者对象,只要继承自UIResponder
的类,才能处理事件。
UIApplication
、UIView
、UIViewController
都是继承自UIResponder
类,能够响应和处理事件。CALayer
不是UIResponder
的子类,没法处理事件。
事件的分发与传递:
1. alpha <0.01 2. userInteractionEnabled = NO 3. hidden = YES.
响应者链:
响应链是从最合适的view开始传递,处理事件传递给下一个响应者,响应者链的传递方法是事件传递的反方法,若是全部响应者都不处理事件,则事件被丢弃。咱们一般用响应者链来获取上几级响应者,方法是UIResponder
的nextResponder
方法。
NSString *str1 = [NSString stringWithFormat:@"hello"]; NSString *str2 = @"hello"; NSString *str3 = @"hello"; if (str1 == str2) { NSLog(@"str1 = str2"); } if (str2 == str3) { NSLog(@"str2 = str3"); } if ([str1 isEqualToString:str2]) { NSLog(@"str1 isEqualToString:str2"); }
输出以下:
str2 = str3 str1 isEqualToString:str2
这里考察的是常量池相关的知识点
isEqualToString
比较的是两个字符串的内容;
而==
比较的是地址的引用;
这里str2 == str3
返回true
,主要是与常量池有关;在给str2赋值的时候,将hello一块儿放入了常量池中,当再次将hello赋值给str3的时候,先从常量池中查看是否存在hello的值,若是有,则直接取出。因此str2和str3指的是同一个引用,所以返回的结果天然是true
扩展: iOS程序中的内存分为:堆区、栈区、全局区(静态区)、常量区、方法区