52个有效方法(6)

属性

“属性”(property)是OC的一项特性,用于封装对象中的数据。

@property

//  Man.h
#import <Foundation/Foundation.h>

@interface Man : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSString *sex;
@end

与下面的写法等效

//  Man.h
#import <Foundation/Foundation.h>

@interface Man : NSObject
{
    // 实例变量
    NSString *name;
    NSString *sex;
}
// setter
- (void)setName:(NSString *)newName;

// getter
- (NSString *)name;

// setter
- (void)setSex:(NSString *)newSex;

// getter
- (NSString *)sex;
@end
  1. 省时,省力 :如果使用了属性,编译器会自动编写访问属性所需的方法。这个过程由编译器在编译期执行,看不到这些get set 源代码。

  2. 编译器会自动向类中添加适当类型的实例变量,并且在属性名前添加下划线。

@synthesize

@dynamic

//  Man.h
#import <Foundation/Foundation.h>

@interface Man : NSObject
@property (nonatomic,strong)NSString *name;
@end
//  Man.m
#import "Man.h"

@implementation Man
@dynamic name;
// setter
// - (void)setName:(NSString *)name
// {
//   _name = name;
// }
// getter
- (NSString *)name
{
  return _name;
}
@end

调用时会出现崩溃

    Man *man = [[Man alloc] init];
    man.name = @"sky";//缺 setter 方法会导致程序崩溃
    NSString *name = man.name;//缺 getter 方法同样会导致崩溃

属性特质

原子性

存取器控制

//setter=<name>这种不常用,也不推荐使用
@property (nonatomic, setter = mySetter,getter = myGetter ) NSString *name;
  

@property (nonatomic,getter = isHidden ) BOOL hidden;

内存管理

举例说明weakstrongcopy属性特质的差异

@property (nonatomic,strong) Person *strongPerson;
@property (nonatomic,weak) Person *weakPerson;
self.strongPerson = [[Person alloc] init];
self.weakPerson = self.strongPerson;
self.strongPerson = nil; 
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果为:strongStr=(null),weakStr=(null) 。说明weak修饰的属性并不会使引用计数增加。

@property (nonatomic,strong) NSString *strongStr;
@property (nonatomic,weak) NSString *weakStr;
···
self.strongStr = @"string";
self.weakStr = self.strongStr;
self.strongStr = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongStr,self.weakStr);

输出结果为:strongStr=(null),weakStr=string 。这里主要是因为NSString类型的赋值默认会加上copy,而copy会创建一个新的对象。这里的赋值语句其实是

self.strongStr = [@"string" copy];
self.weakStr = [self.strongStr copy];
self.strongPerson = [[Person alloc] init];
self.weakPerson = self.strongPerson;
self.weakPerson = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果如下:strongStr=<Person: 0x600000007d50>,weakStr=(null) 。说明weak修饰的属性只是对对象的弱引用,并不会真正的持有该对象。

Person *p = [[Person alloc] init];
self.strongPerson = p;
self.weakPerson = self.strongPerson;
p = nil; 
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果为:strongStr=<Person: 0x600000200b50>,weakStr=<Person: 0x600000200b50> 。因为strong属性会强引用该对象并使该对象的引用计数+1,所以即使把p设置为nil,该对象也并没有释放,要想释放该对象,还得把strongStr设置为nil:self.strongPerson = nil; 。这样输出结果才为 strongStr=(null),weakStr=(null)

NSString *a = @"xiaoming";
Person *p = [[Person alloc] init];
p.name = a;
NSLog(@"before p.name=%@",p.name);
a = @"xiaohua";
NSLog(@"after p.name=%@",p.name);

输出结果:before p.name=xiaoming after p.name=xiaoming。因为copy关键字修饰的属性是将对象拷贝一份赋值,所以你改变原对象并不会对拷贝后的对象有任何改变。

注:用@property声明 NSStringNSArrayNSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableStringNSMutableArrayNSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份.

要点

  1. 可以用@property语法来定义对象中所封装的数据。

  2. 通过“修饰词”来指定存储数据所需的正确语义。

  3. 在设置属性所对应的实例变量时,一定要遵从该属性所声明的语义。

  4. 开发iOS程序时应该使用nonatomic属性,因为atomic(同步锁)属性严重影响性能。

52个有效方法(6)

全文结束