iOS 52个技巧学习心得笔记 第二章 对象 , 消息, 运行期

1. 属性

在开发过程中经常要用到定义属性,@property和@synthesize是经常用到的属性, property在.h文件中作声明,@synthesize在.m文件中用于实现
//  Student.h
//  property
//
//  Created by Rio.King on 13-8-25.
//  Copyright (c) 2013年 Rio.King. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Student : NSObject
{
    int age;
    int no;
}

//当编译器遇到@property时,会自动展开成getter和setter的声明
@property int age;
@property int no;


@end


Student.m

//
//  Student.m
//  property
//
//  Created by Rio.King on 13-8-25.
//  Copyright (c) 2013年 Rio.King. All rights reserved.
//

#import "Student.h"

@implementation Student

//@synthesize 会自动生成getter和setter的实现
//@synthesize 默认会去访问age,no,height同名的变量,,
//如果找不到同名的变量,会在内部自动生成一个私有同名变量age,no,height,,
//因此Student.h 中的这几个变量也可以省略不写。
@synthesize age,no;

@end
说明:在xcode4.5以后 可以省略@synthesize ,编译器会自动帮你加上getter 和 setter 方法的实现,并且默认会去访问_age这个成员变量,如果找不到_age这个成员变量,会自动生成一个叫做 _age的私有成员变量.
 而我在实际开发使用上的经验是 尽量使用”点语法”,可读性更强.涉及setter  getter  初始化时候我才会使用_age.
例如:



#pragma mark - getter and setter
//当有实例方法中调用 “self.titleLab”就会自动调用以下 setter getter 方法 (UILabel *)titleLab
{
    if(!_titleLab){
        UILabel * titleLab = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.width, HF_BUTTON_HOME_TEST_HEIGHT)];
        titleLab.textAlignment = NSTextAlignmentCenter ;
        titleLab.text = @"选择生日";
        titleLab.font = HF_TITLE_BOLD_FONT ;
        [self.view addSubview:titleLab];
        _titleLab = titleLab;
    }
    return _titleLab;
}
2, 认识几个关键字
(1)atomic:原子操作(线程安全) (原子性 是指事物的一个完整操作,操作成功就提交,反之就回滚.原子操作 指的是具有原子性的操作)

OC属性设置里面默认是atomic 原子属性,意思是 setter/getter函数就是一个原子操作,如果多线程操作 setter 那么 相当于 在函数头尾加了锁 防止资源竞争造成的死锁.(不会出现某一个线程执行完setter所有语句之前,另一个线程就开始执行setter)
(2)nonatomic:非原子操作(线程不安全) 一般不需要多线程支持的时候 就用 nonatomic.这样并发访问的效率就会比较高.如果 一个属性要在多线程中使用,那么 就该用原子属性的atomic.

但是 在开发iOS程序时应该使用nonatomic属性,因为atomic属性会严重影响性能, 我们一般在使用nonatomic过程中加锁之类的方法做到数据同步.
通常说nonatomic 是提高在非多线程应用中的读写效率

如果问 这俩谁是线程安全的,原子性安全 所以是atomic更安全 

@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
区别 使用@synthesize,编译器会确实的产生getter和setter方法,而@dynamic仅仅是告诉编译器这两个方法在运行期会有的,无需产生警告。

(3)synthesize  会自动生成getter和setter的实现 如果不实现setter和getter方法,编译器将会自动在生产setter和getter方法
(4) dynamic  就是要来告诉编译器,代码中用@dynamic修饰的属性,其getter和setter方法会在程序运行的时候或者用其他方式动态绑定,以便让编译器通过编译。其主要的作用就是用在NSManageObject对象的属性声明上,由于此类对象的属性一般是从Core Data的属性中生成的,Core Data框架会在程序运行的时候为此类属性生成getter和Setter方法。
     假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。这个 时候 自己要写实例方法 进行getter  读取 或者 setter 进行赋值(注意防止方法自己调用自己 造成死循环)

正确使用举例:

#pragma mark - getter and setter

- (UILabel *)noteLabel
{
    if (!_noteLabel) {//_noteLabel在这里是私有创建, 在@dynamic 里不会自己生成
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 64.0 + 22.0, SCREEN_WIDTH - 100, 40.0)];
        [label setTextAlignment:NSTextAlignmentCenter];
        [label setFont:[UIFont boldSystemFontOfSize:16.0]];
        [label setTextColor:[UIColor grayColor]];
        [label setText:self.noteText];
        [label setNumberOfLines:0];
        [label setLineBreakMode:NSLineBreakByWordWrapping];
        
        _noteLabel = label;
    }
    return _noteLabel;
}

(4)assign : 简单赋值操作,不更改索引计数
对基本数据类型 (例如NSInteger,CGFloat)和C数据类型(int, float, double, char, 等)       适用简单数据类型
(5)strong :我习惯叫它”强引用(apple说是strong reference)”(书上管它叫 拥有关系(owning relationship)) 当前对象被其他对象引用时,会执行retain操作,引用计数器+1。当retainCount=0时,该对象才会被销毁。因为我们要进行对象的内存管理,所以这是默认的引用方式。(默认是强引用)
           一个对象只有在它的所有强引用都被释放后才能被回收.
(6)weak   :”弱引用”(非拥有关系 nonowning relationship) 当它的生存周期到了时就会被销毁,弱引用在可能会出现循环引用的情况下是必不可少的. 

strong VS weak
强引用持有对象  弱引用 不持有  当弱引用指向一个强引用所持有的对象时,当强引用赋值为nil 弱引用自动被赋值nil
如果弱引用被赋值为nil  强引用依旧持有原来的对象


strong,weak, unsafe_unretained往往都是用来声明属性的如果想声明临时变量就得用__strong,  __weak, __unsafe_unretained,  __autoreleasing, 其用法与上面介绍的类似。


(7)retain :手动释放内存时候使用,相当于ARC中的strong 

(8)copy :(浅拷贝,指针拷贝)a 和 b 指向同一个对象  共用同一块内存
(9)mutable:(深拷贝,内容拷贝) 做”影子数据”时候使用 是完全新的一个对象

举例:1
      NSString *string = @"origion";
      NSString *stringCopy = [string copy];
      NSMutableString *stringMCopy = [string mutableCopy];
      
      [stringMCopy appendString:@"!!"];
     //内存
     NSLog(@"
 string:%p 
 stringCopy:%p 
stringMCopy:%p 
",string,stringCopy,stringMCopy);
     //对象
     NSLog(@"
 string:%@
stringCopy:%@
stringMCopy:%@
”,string,stringCopy,stringMCopy);

    2016-02-16 17:35:04.284 dailylife[1665:183019]
    string:0x10d58a4d0
    stringCopy:0x10d58a4d0 //copy -> 和string 共用同一块内存地址 (同一个指针)
    stringMCopy:0x7f92e47375d0 //multableCopy 新的一块内存指针
    2016-02-16 17:35:21.479 dailylife[1665:183019]
    string:origion
    stringCopy:origion // copy -> 同一个对象
    stringMCopy:origion!! //multableCopy 一个新对象
举例2
NSMutableString *string = [NSMutableString stringWithString: @"origion"];
     NSString *stringCopy = [string copy];
     NSMutableString *mStringCopy = [string copy];
     NSMutableString *stringMCopy = [string mutableCopy];

     //[mStringCopy appendString:@“mm"];//error 可变字符串应该使用”可变拷贝”multableCopy 才可使用 这类方法
     [string appendString:@" origion!"];
     [stringMCopy appendString:@"!!"];
     
    //内存
    NSLog(@"
 string:%p 
 stringCopy:%p 
 mStringCopy :%p
stringMCopy:%p 
",string,stringCopy,mStringCopy,stringMCopy);
    //对象
    NSLog(@"
 string:%@
stringCopy:%@
mStringCopy:%@
stringMCopy:%@
”,string,stringCopy,mStringCopy,stringMCopy);
   
2016-02-16 17:54:46.019 dailylife[2039:201349]
string:0x7ff993f71800
stringCopy:0x7ff993f71860
mStringCopy :0x7ff993f71880
stringMCopy:0x7ff993f718a0   //四个不同对象不同指针
    
2016-02-16 17:54:48.107 dailylife[2039:201349]
string:origion origion!
stringCopy:origion
mStringCopy:origion
stringMCopy:origion!!        //四个不同对象不同指针
原文地址:https://www.cnblogs.com/someonelikeyou/p/5201694.html