一、@property中属性关键字介绍
1、strong:释放旧对象将旧对象的值赋予输入对象,再提高输入对象的索引计数为1,此关键字经常使用。
2、weak:不增加引用计数,不持有对象,因此也不能决定对象释放,对比assign的一个好处是,当对象消失时指针自动归为nil。
3、assign:适用于基础数据类型(NSInteger、CGFloat、...)不增加引用计数。
4、copy:建立一个索引计数为1 的对象然后释放旧对象,此属性只对那些实行了NSCopying协议的对象类型有效(NSString、Block)。
5、atomic和 nonatomic用来决定编译器生成的getter和setter是否为原子操作,atomic设置成员变量的@property属性时默认为是atomic 提供线程安全。
6、nonatomic:非原子性访问对于属性赋值的时候不加锁,多线程并发访问会提高性能,如果不加此属性则默认是两个访问方法都为原子型事务访问。
7、readonly:此标记说明属性是只读的。
8、readwrite:此标记说明属性会被当成读写的,这也是默认的。
9、unsafe_unretained:跟weak类似,声明一个弱引用,但是当引用计数为0时,变量不会自动设置为 nil(ios5加入的)。
10、.具体一点:IBOutlet可以为weak,NSString为copy,Delegate一般为weak,其他的看情况。一般来说,类“内部”的属性设置为strong,类“外部”的属性设置为weak。说到底就是一个归属权的问题。小心出现循环引用导致内存无法释放。不用ARC的话就会看到很多retian。如果你写了@synthesize abc = _abc;的话,系统自动帮你声明了一个_abc的实例变量。
使用assign: 对基础数据类型 (NSInteger)和C数据类型(int, float, double, char,等)
使用copy: 对NSString
使用retain: 对其他NSObject和其子类
二、iOS中property和synthesize的详细说明
1、一般我们需要定义声明一个属性的时候就要用到它。但是,让我们回想到一个最原始的类的创建,在objective-c中,类在默认情况下是protected的,也就是说,只有本类或者是有继承关系的类才能够拿到这个类的属性进行操作,那么,如果其他类想要操作这些属性就没有办法了。所以,如果我们需要这样的操作,那么就要在这个类里面为属性写上setter和getter方法,来为其他类提供一个类似于接口的东西来操作本类的属性,所以,最原始的类里面应该是这样写的:
@interface Student : NSObject
{
//age和gender这两个属性的声明
int age;
int gender;
}
//age的getter和setter方法声明
- (int)age;
- (void)setAge:(int)newAge;
//no的getter和setter方法声明
- (int)gender;
- (void)setGender:(int)newGender;
@end
但是,如果有一个类有100个属性,那么我们就得写100个getter和100个setter方法,那样的话,类里面的内容就会很庞大杂乱。因此,property的出现正是为了解决这个问题。就是用property声明的属性会自动去声明setter方法和getter方法,不用我们去手动书写。同时,也可以发现,使用property定义的属性,都可以为属性定义一些说明性的参数,比如我们常用的nonatomic,copy,assign等等。
2、接着是synthesize,大家最熟悉的应该是这两种写法(这里使用student代表任意一个属性)@synthesize student; 以及 @synthesize student = _student
其实,@synthesize student;写法等价于 @synthesize student =_student,
提完了这点,相信大家也都有所明白,有些开发者喜欢直接使用下划线加上属性名来进行操作,有些开发者喜欢使用self.student这种形式来书写,在ARC的机制下两者表面上的差别不是很大,但是有一点需要我们去理解清楚的是(这里说明的情况是xcode4.5以后的版本)synthesize的作用就是让student = ?中的后者这个变量来“代替”属性,从而可以通过操作变量来进行属性的操作,但是有一点最关键的是,使用变量进行操作,属性本身的引用计数是不会增加的,因为没有经过调用setter方法或者是getter方法。但是如果使用self.student这种操作方式的话,实质上是通过setter或者是getter方法进行操作,引用计数会随着不同的操作而改变,了解了这点后就能够更好的避免内存泄露问题。另外,synthesize会自动地生成setter方法和getter方法的实现。通过这些了解,我们知道了使用property和synthesize确实大大优化了我们的代码,让我们的代码看起来更加精简。
三、@dynamic有什么作用?
@dynamic:告诉编译器,不自动生成getter和setter方法,避免编译期间产生警告,然后由自己实现存取方法或者在运行时动态创建绑定。主要使用在CoreData实现NSManagedObject子类时使用,由CoreData框架在程序运行时动态生成子类属性。
四、ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?
在编写代码时,@property什么都不写的话,会怎么样呢!大家有没有想过?
@property NSString *name;
我没有写任何属性关键字,其实这样也会有默认的属性关键字。
@property (strong, atomic, readwrite) NSString *name;
五、用@property声明的NSString、NSArray、NSDictionary经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
copy所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用copy来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。
六、@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?
1、如果指定了成员变量的名称,会生成一个指定名称的成员变量。
2、如果这个成员变量已经存在了就不再生成了。
3、如果是@synthesize foo;会生成一个名称为foo的成员变量,也就是说:如果没有指定成员变量的名称会自动生成一个属性变量同名的成员变量。
4、如果 @synthesize foo = _foo;不会生成成员变量(实例变量)。
假如property名为foo,存在一个名为 _foo的实例变量,那么不会自动合成新变量了。
七、UIAlertController的使用方法
iOS 8新增加了UIAlertController控制器,用之前的UIAlertview和actionSheet会报警告,这个控制器可以实现警告框和操作表,非常的方便。使用UIAlertController的优势在于不仅可以添加按钮,还可以添加文本框和自定义视图到警告框和操作表中;相应时间可以通过闭包实现,而不用委托协议实现。下面我就介绍UIAlertController的基本使用方法。
-(void)creatAlertController_sheet {
/*
先创建UIAlertController,preferredStyle:选择UIAlertControllerStyleActionSheet,这个就是相当于创建8.0版本之前的UIActionSheet;
typedef NS_ENUM(NSInteger, UIAlertControllerStyle) {
UIAlertControllerStyleActionSheet = 0,
UIAlertControllerStyleAlert
} NS_ENUM_AVAILABLE_IOS(8_0);
*/
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"标题" message:@"注释信息,没有就写nil" preferredStyle:UIAlertControllerStyleActionSheet];
/*
typedef NS_ENUM(NSInteger, UIAlertActionStyle) {
UIAlertActionStyleDefault = 0,
UIAlertActionStyleCancel, 取消按钮
UIAlertActionStyleDestructive 破坏性按钮,比如:“删除”,字体颜色是红色的
} NS_ENUM_AVAILABLE_IOS(8_0);
*/
// 创建action,这里action1只是方便编写,以后再编程的过程中还是以命名规范为主
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"标题1" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击了按钮1,进入按钮1的事件");
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击了取消");
}];
UIAlertAction *action3 = [UIAlertAction actionWithTitle:@"删除" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
//跳到创建alertview的方法,一般在点击删除这里按钮之后,都需要一个提示框,提醒用户是否真的删除
[self creatAlertController_alert];
}];
//把action添加到actionSheet里
[actionSheet addAction:action1];
[actionSheet addAction:action2];
[actionSheet addAction:action3];
//相当于之前的[actionSheet show];
[self presentViewController:actionSheet animated:YES completion:nil];
}
//创建一个alertview
-(void)creatAlertController_alert {
//跟上面的流程差不多,记得要把preferredStyle换成UIAlertControllerStyleAlert
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"标题" message:@"注释信息,没有就写nil" preferredStyle:UIAlertControllerStyleAlert];
//可以给alertview中添加一个输入框
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"alert中的文本";
}];
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"标题1" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击了按钮1,进入按钮1的事件");
//textFields是一个数组,获取所输入的字符串
NSLog(@"%@",alert.textFields.lastObject.text);
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击了取消");
}];
[alert addAction:action1];
[alert addAction:action2];
[self presentViewController:alert animated:YES completion:nil];