programmingwithobjectivec学习笔记(三)

Encapsulating Data 

封装数据

Properties Encapsulate an Object’s Values 

用属性来封装对象的值

@interface XYZPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
定义了2个属性firstName  lastName,定义属性是为了控制访问权限


Use Accessor Methods to Get or Set Property Values 

使用get(获取)和set(设置)来访问属性(编译器会自动生成)

//设置属性

NSString *firstName = [somePerson firstName];
[somePerson setFirstName:@"Johnny"];

如果你不想对象被修改则可以加上readonly 代表该属性只有get方法没有set方法

@property (readonly) NSString *fullName;
readwrite//默认的无需定义

readonly//只读

//为获取及设置器方法命名,如下,把get方法命名为isFinished(对于BOOL类型的get方法习惯上以is作为开头)

//这样设置后程序将只认得isFinished方法,二不认得getter

@property (getter=isFinished) BOOL finished;
如果需要对属性设置多个参数则中间加逗号,如下

@property (readonly, getter=isFinished) BOOL finished;

Dot Syntax Is a Concise Alternative to Accessor Method Calls

用点来调用类方法和属性


//类似下面这样调用
        NSString *firstName=somePerson.firstName; //实例somePerson的firstName属性
        somePerson.firstName =@"Johnny"; 



 ●   Getting a value 获取值

somePerson.firstName 等价于   [somePerson firstName]  ?????两种方法取舍,用那种?

 ●   Setting a value设置值

somePerson.firstName= @"Johnny"  等价于  [somePerson setFirstName:@"Johnny"] 

Most Properties Are Backed by Instance Variables 

大多属性依靠实例变量支持

你可以用以下方法获取属性

  - (void)someMethod { 
        NSString *myString       =   @"An interesting string"; 
        _someString      =  myString; //_someString就是实例变量(instance variables)
   } 

但是一般情况下使用self获取如下

  - (void)someMethod { 
        NSString *myString      =    @"An interesting string"; 
        self.someString     =    myString; 
     // or 
       [self setSomeString:myString]; 
   } 

You Can Customize Synthesized Instance Variable Names 

你可以自定义实例变量的名称

//定义

@interface  YourClass :NSObject{

NSString *  instanceVariableName;

}


@end


//实现
  @implementation YourClass 

  @synthesize propertyName=instanceVariableName; 
   ... 
  @end 

举例如下:
  @synthesize firstName= ivar_firstName; 

这个例子中属性任然叫 firstName,set,get方法名也不变,不过对应的实例变量名为ivar_firstName


如果你没定义实例变量名如下:

@synthesize firstName

实例变量名会默认和属性名一样叫firstName


You Can Define Instance Variables without Properties 

你可以定义实例变量却不定义属性(尽量不要这么用)

实例变量-》外部用

属性-》内部用

如下,要写在interface后的中括号中

  //定义接口文件

@interface SomeClass : NSObject { 

//在此定义实例变量

        NSString *_myNonPropertyInstanceVariable; 
  } 
   ... 
  @end
//实现文件
  @implementation SomeClass { 

//或者在此定义实例变量
        NSString *_anotherCustomInstanceVariable; 
  } 
   ... 
  @end 

你也可以在类扩展中(extension)中定义实例变量


Access Instance Variables Directly from Initializer Methods 

在初始化函数中房屋实例变量

一个典型的初始化函数

  - (id)init { 

//实例化父类其实就是继承父类的成员方法和变量这个必须放在第一行,是实例化类的顺序
        self  = [super init]; 
        if (self) { //判断非nil
             // initialize instance variables here 
        } 
        return self; 
  } 


如下例子

如此定义
  - (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName; 
如此实现
  - (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName { 
        self       [super init];
        if (self) { 
              _firstName    =aFirstName; 

             _lastName     =   aLastName; 
        } 
        return self; 
   } 


The Designated Initializer is the Primary Initialization Method 

主要初始化函数

如果你有多个初始化函数,则要决定哪个是主要的初始化函数(一般是参数最多的那个作为主要初始化函数,其他初始化函数都调用该函数)

你可以这样定义一个初始化函数作为主初始化函数

//init开头的函数代表的是构造函数、必须返回id或者本类对象

- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName {return [self initWithFirstName:aFirstName lastName:aLastName dateOfBirth:nil];

//其他初始化函数

-(id)init {
    return [self initWithFirstName:@"John" lastName:@"Doe" dateOfBirth:nil];


You Can Implement Custom Accessor Methods 

你可以自定义访问器方法

//下面有一个属性

@property (readonly) NSString *fullName;
//定义属性的访问器方法

- (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];

如果你要自定义一个访问器来访问一个实例变量(instance variable)你应该如下写法使用一个“懒惰访问器”

- (XYZObject *)someImportantObject {
    if (!_someImportantObject) {
        _someImportantObject = [[XYZObject alloc] init];
    }
    return _someImportantObject;
}

一般请看下,编译器会为属性自动添加实例变量,但是如果你为属性自定义了一个getter和setter方法(readwrite)或者自定义了一个getter方法(readonly)编译器不会自动创建实例变量(instance variable),这种情况下你仍然要创建实例变量的则要如下方法

@synthesize property = _property;

Properties Are Atomic by Default (???????线程概念有待加强)

属性默认是线程安全(atomic)的(多线程情况下永远只有一个对象访问本属性)

@interface XYZObject : NSObject
@property NSObject *implicitAtomicObject;          // atomic by default 默认就是atomic
@property (atomic) NSObject *explicitAtomicObject; // explicitly marked atomic 显示的定义atomic
@end

如果不需要线程安全,可以使用与其想对的有nonatomic,访问速度更快
@interface XYZObject : NSObject
@property (nonatomic) NSObject *nonatomicObject;
@end

Manage the Object Graph through Ownership and Responsibility 


当第一个对象依赖于第二个对象,则说,第一个对象对第二个对象有强引用(strong references  

如图


XYZPerson Object对2个NSString Object有强引用,2个NSString将存在直到XYZPerson对象被重新分配

当XYZPerson对象从内存中被重新分配(deallocated),那么强引用的2个NSString Object也将被重新分配

另一个复杂点的例子

1.2个对象都对@john有强引用




当改变XYZPerson object中firstName的值时候@john任然存在



当再改变XYZBadgeView中firstName的值时候@john被重新分配




Avoid Strong Reference Cycles 

避免循环引用

2个对象对对方都有强引用,会引起strong reference cycle (强引用循环)会造成程序奔溃,所以需要强引用(strong)和弱引用(weak)结合使用

一个对象只要有一个strong(强引用)就不会被重新分配内存

比如一个对象有一个强引用一个弱引用,强引用被重新分配,改对象也会被重新分配,弱引用会变成指向nil

如下面例子




arc机制概念请看http://onevcat.com/2012/06/arc-hand-by-hand/

Use Strong and Weak Declarations to Manage Ownership 


用强/弱引用赖控制权限

//默认情况下定义的属性都是强引用

@property id delegate;

如果要定义一个弱引用类型

@property (weak) id delegate;

Local variables (and non-property instance variables) also maintain strong references to objects by default.This means that the following code will work exactly as you expect:

本地变量和没有属性的实例变量也默认对object保持强引用

@property NSTableView *tableView;
@property id delegate;
@property (weak) id delegate;
 
       
 
       
//例子
NSDate *originalDate = self.lastModificationDate;
self.lastModificationDate = [NSDate date];
NSLog(@"Last modification date changed from %@ to %@",
                    originalDate, self.lastModificationDate);
这个例子中,orginalDate对实例变量lastModificationDate具有强引用,当一个强引用lastModificationDate改变了,对象仍然保存在另一个强引用的originalDate中

一个变量的强引用保持到改变量被重新分配或者赋值为nil


如果你不希望便利保持强引用那么使用 __weak

NSDate * __weak originalDate = self.lastModificationDate;
self.lastModificationDate = [NSDate date];

这个例子中,当lastModificationDate改变的时候,originalDate会被重新分配并赋值为nil


警告:千万不要像如下定义

NSObject * __weak someObject = [[NSObject alloc] init];
someObject只有弱引用指向NSObject的实例,没有强引用指向NSObject的实例,someObject会立即变成nil


弱引用的强引用

//在一个函数中你可能会需要多次访问一个弱引用
- (void)someMethod {
    [self.weakProperty doSomething];
    ...
    [self.weakProperty doSomethingElse];

// 你想确保其不会被重新分配直到你不需要为止,你可以用一个强引用指向这个弱引用,如下范例:

- (void)someMethod {
    NSObject *cachedObject = self.weakProperty;
    [cachedObject doSomething];
    ...
    [cachedObject doSomethingElse];

In this example, the cachedObjectvariable maintains a strong reference to the original weak property valueso that it can’t be deallocated as long ascachedObjectis still in scope (and hasn’t been reassigned anothervalue). 

只要 cachedObject任然在作用域内(in scope)并且没有被重新赋值 weakProperty就不会重新分配


在多线程编程中,弱引用很可能在函数调用中不知不觉被重新分配了,为了严谨,最好如下使用弱引用

NSObject *cachedObject = self.someWeakProperty; //1 定义一个强引用指向弱引用对象

if (cachedObject) { //2 判断强引用的对象是否为空

[someObject doSomethingImportantWith:cachedObject]; //3 使用对象

} //4

cachedObject = nil; //5 把强引用设置为nil,释放弱引用,弱引用被重新分配

In this example, the strong reference is created in line 1, meaning that the object is guaranteed to be alive forthe test and method call. In line 5,cachedObjectis set to nil, thereby giving up the strong reference. If theoriginal object has no other strong references to it at this point, it will be deallocated and someWeakPropertywill be set tonil


Use Unsafe Unretained References for Some Classes (NSTextView,NSFont、NSColorSpace 等不支持weak引用的类,使用unsafe_unretained类似于weak


If you need to use a weak reference to one of these classes, you must use an unsafe reference. For a property,this means using theunsafe_unretainedattribute:

//设置非安全非保留属性
@property (unsafe_unretained) NSObject *unsafeProperty;

For variables, you need to use__unsafe_unretained:

//设置非安全非保留变量
NSObject * __unsafe_unretained unsafeReference;

An unsafe reference is similar to a weak reference in that it doesn’t keep its related object alive, but it won’tbe set tonilif the destination object is deallocated. This means that you’ll be left with a dangling pointer tothe memory originally occupied by the now deallocated object, hence the term “unsafe.” Sending a messageto a dangling pointer will result in a crash. 

unsafe_unretained 类似于weak,但是区别在于,当unsafe_unretained 指向的对象被重新分配,unsafe_unretained的属性或变量不会被设置成nil,变成了一个指向空引用的指针,会引起程序崩溃

 
    
    

Copy Properties Maintain Their Own Copies (Copy关键字的应用)

修改对象内容却保持引用

//NSMutableString是一个可变的String,与NSString不同,通过其自带方法改变其值(非重新实例化)不会改变其他对象对其的强弱引用

例子如下:

NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
现在 self.badgeView.firstName指向的对象与nameString一致

接下来通过NSMutableString的appendString方法追加字符john

[nameString appendString:@"ny"];
结果是self.badgeView.firstName任然指向的对象与nameString一致都变为了johnny

但是使用copy关键字可以打破这种关系

@interface XYZBadgeView : NSView
@property (copy) NSString *firstName;
@property (copy) NSString *lastName;
@end

NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
[nameString appendString:@"ny"];
上面例子中 self.badgeView.firstName是nameString的一个副本,当nameString的值被追加后,nameString对象的值变成了johnny,然而 self.badgeView.firstName值任然保持不变,为john

PS:任何要实现copy属性的对象必须支持NSCopying(如下例子)

@interface CommonObj : NSObject<NSCopying>

@end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值