OC基础

Oc基础

1、#import的用途

1>#import与#include一样,拷贝文件的内容

2>可以自动防止文件的内容被重复拷贝

2、#import

        NSLog(<#NSString * _Nonnull format,…#>)声明的函数

3、Foundation框架头文件路径

1>、Xcode右击,显示报内容

2>、/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks

4、主头文件

1>、最主要的头文件,名字一般跟框架名一样,包含框架中所有的其他文件

2>、Foundation框架的主头文件名称就是Foundation.h

3>、只要包含了Foundation的主头文件,就可以使用整个框架的东西

5、运行过程

1>编写代码  .m .c

2>编译  xxx.m xxx.c

3>链接  xxx.o xxx.o

4>运行    ./a.out

6、在使用类的时候,会将类加载到内存中

没有对象内部都有一个isa指针,这个指针指向类的方法列表

7、方法与函数的区别

方法:

1>对象方法以-号开头

2>方法的声明必须写在@interface@end之间

       方法的实现必须写在@implementationend之间

3>对象方法只能又对象来调用

4>对象方法归对象和类拥有

函数:

1>函数可以写在文件的任意位置,函数归文件所有

2>函数的调用不依赖于对象

8、匿名对象

就是创建对象的时候,没有指针去指向这个对象

9、类方法和对象方法可以同名

类方法的执行效率比较高,但是类方法不能访问成员变量

10、工具类:基本没有任何成员变量的时候,里面的方法都是类方法。

11、继承

1>子类不能拥有和父类相同的成员变量

2>父类必须声明在子类之前

3>调用某个对象的方法,优先从该对象中查找,如果找不到再去父类中查找方法的实现

每个类中都有一个superClass指针,指向自己的父类,进而才可以去

super关键字的使用

1>super直接调用父类的方法

2>具体调用super的对象方法还是类方法,完全取决于当前的环境

3>子类中想先调用父类的方法之后,才去调用子类的方法时候,可以调用下super的方法

12、多态:父类的指针指向子类的对象 (狗 是DOG类型 ,它的父类是animation。所以一个狗的对象既可以用狗类的对象指针指向,也可以用动物类对象的指针指向)

1>没有继承就没有多态

2>如果函数的参数是父类,那么参数对象可以传子类、父类对象

3>局限性:父类类型的变量不能直接调用子类类型特有的方法

13、成员变量的作用域

局部变量、全局变量有自己的作用域,成员变量也不例外。

成员变量的作用域:

@public:在任何地方都能访问对象的成员变量             

@private:只有当前类的对象方法中访问    或者是用set/get方法 @implementation中声明的成员变量默认是private

@protected:可以在当前类以及子类的对象中直接访问(默认就是@protected)或者是用set/get方法

@package:只要处于同一框架,就可以直接访问对象的成员变量

@implementation中也能定义一个成员属性,但是默认是私有的

@interface@implementation不能声明同名的成员属性

14、@property  int age;会自动生成setAgeage方法的声明

@synthesizeage = _age;会自动声明setAgeage方法的实现,而且这句话会访问_age这个属性,如果不存在就会自动帮我们创建一个@private_age属性。

@synthesizeage(如果不写=_age)会自动声明setAgeage方法的实现,而且这句话会访问_age这个属性,如果不存在就会自动帮我们创建一个@privateage属性。

Xcode4.3之后@property  int age这一句代码就会帮我们生成 _age 以及setAgeage的方法声明与实现,但是这个方法生成的成员属性是私有的,不能让子类进行访问,如果想让子类进行访问,那么就需要在.h中声明声明一个protected_age属性

如果手动实现了set方法,那么编译器就只会生成get方法和下划线属性

如果手动实现了get方法,那么编译器就只会生成set方法和下划线属性

如果手动生成了setget方法,那么编译器就不会帮你生成下划线属性

15、构造方法

用来初始化对象的方法,是一个对象方法

重写init方法:

1>调用【super init】方法初始化父类的属性,并赋值给self

2>判断self是否为空,不为空则进行初始化属性操作

3>返回self

重写构造方法的目的:为了创建对象的时候,成员变量就有值

-(instancetype)init{

    if(self=[superinit]){

        _age  =10;

    }

    returnself;

}

自定义构造方法:

1>一定是对象方法,以 - 开头

2>返回类型是 id类型

3>方法名以initWith开头

-(instancetype)initWithAge:(int)age{

    if(self=[superinit]){

        _age = age;

    }

    returnself;

}

16、修改Xcode创建文件的时候的一些配置属性

/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates在这里面修改

17、分类:可以给某一类扩展一些方法,在不改变原来类的基础上,为类增加一写方法。

分类的使用注意:

1>只能增加方法,不能只能成员变量

2>分类方法的实现中可以访问原来类的成员变量

3>分类可以重新实现原来类中的方法,但是会覆盖掉原来类中的方法,会导致原来类中的方法无法使用

4>方法调用的优先级: 分类(最后编译的分类优先) —> 原类 —> 父类

18、

1>当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用类和分类的+ (void)load{   

}方法,只会调用一次

2>当第一次使用某个类的时候,会调用当前类的+(void)initialize

}方法

3>先加载父类,再加载子类,最后加载分类的(先调用父类的load方法,再调用子类的load方法)

先初始化父类,再初始化子类(先调用父类的initialize方法,再调用子类的initialize方法)

19、类也是个对象

类也是一个对象,是一个class类型的对象,简称类对象

Class类型的定义

typedefstructobjc_class * Class

类名就代表类对象,每个类只有一个对象

20、-(NSString *)description{}方法

默认情况下,利用NSLog和%@输出对象的时候,结果是<类名:内存地址>

1>会调用对象的description方法

2>拿到description方法的返回值展示到屏幕上

3>description默认返回的是“类名+内存地址”

+(NSString *)description{}方法,类的-(NSString *)description{}方法,默认返回的是类名

21、    NSLog(@"%s",__FILE__);

NSLog输出c语言字符串的时候,不可以包含中文

22、SEL

typedefstructobjc_selectorSEL

SEL s = NSSelectorFromString(@"test")

NSStringFromSelector(@selector(test))

_cmd代表当前方法

 NSString *s = NSStringFromSelector(_cmd);

SEL其实是对方法的一个包装,去找到对应的方法地址就可以调用此方法

内存管理   

1、局部变量的对象是放在栈中的,系统会管理他们的内存

     一个oc对象的内存是放在堆中的,需要我们去手动管理他的内存

2、每个对象的内部都有四个字节来存储对象的内存空间

当一个对象alloc /new /copy的时候引用计数器会+1

给对象发送 retain 消息的时候,对象的引用计数器+1

        给对象发送release消息的时候,对象的引用计数器-1

        给对象发送 retainCount 消息的时候,返回对象的引用计数器的个数

3、对象销毁

       当一个对象的引用计数器为0的时候,系统会给对象发送一个dealloc消息,一般重写此方法在其中做一些释放性的操作

4、野指针: 指针指向了一块已经释放的内存对象(这个对象成为僵尸对象)给野指针发送消息会报错 野指针经常报错为 EXC_BAD_ADRESS

      空指针:没有指向任何对象的指针(存储的为nil/NULL/0) oc中给nil 发送消息不会报错

      僵尸对象:所占用的内存已经被回收的对象,僵尸对象不能再继续使用

5、retain方法会返回对象本身

      release方法不会有返回值

6、delloc

      当对象要被回收的时候会调用、一定要调用【super delloc】,因为【super delloc】中也要做一些释放操作,而且这一句一定要写在最后

7、alloc/new/mutableCopy来创建对象的时候,引用计数器会+1,不使用这个对象的时候,需要将引用计数器-1

8、谁retain了,谁就要release

9、当你想使用或者占有某个对象的时候,需要对对象进行一次retain操作

      当你不想使用或者占有某个对象的时候,需要对对象进行一个release操作

      谁retain谁release

      谁alloc谁release

10、假如person  有一个car属性

_car:直接访问成员属性

self->_car:直接访问成员属性

self.car  :get方法

[self car]:get方法

11、MRC中的set方法 

@interfacePerson : NSObject

{

    Car *_car;

}

-(void)setCar:(Car *)car;

-(Car *)car;

@end

@implementationPerson

-(void)setCar:(Car *)car{

    if(_car != car){        //这个判断是为了防止调用多次[self car]此时的car为同一个car,先给_car做一次release操作,此时car已经被释放了,然后再去调用【car retain】方法,这个相当于是给一个僵尸对象发送了一个retain消息。

        [_car release];    //这个是为了防止在你给对象赋值新的car的时候,原有的car没有做release操作,而导致的原有的car不会被释放

        _car =[car retain];//这段代码是为了谁拥有谁就要去retain

    }

}

-(Car *)car{

    return_car;

}

@end

12、内存管理的原则

1>只要调用了alloc,就必须调用release或者autorelease

2>set方法的代码规范

   基本数据类型:

-(void)setAge:(int)age{

_age = age;  直接赋值

}

    对象类型:

-(void)setCar:(Car*)car{

if(_car != car){

[_car release];//对旧对象进行release操作

_car =[car retain];//对新对象进行retain操作

}

}

3>delloc //对self所拥有的所有对象进行一次release操作

-(void)delloc{

[_car  release];

//最后调用【super delloc】

[super delloc];

}

13、property默认生成的set和get方法是直接赋值assign

14、property(retain)就是相当于在set方法中先release旧值,再retain新值

15、property的参数有四个

1>set方法内存管理的相关参数

*retain:先release旧值,再retain新值

*assign:直接赋值

*copy

2>多线程管理

nonatomic :(性能高,set方法的时候不加线程锁)

atomic :(性能低,加线程锁)

3>是否只生成set和get方法

*readwrite:同时生成set和get方法的声明与实现

*readolny:只生成get的声明与实现

4>set和get的方法名称

setter:决定了set:的方法名,一般是需要带冒号的

getter:决定了getter方法名(一般用在bool类型)

例如:

@property(nonatomic,retain,readwrite,setter=setCarrrrr:,getter=carrrrr)Car *car;

16、

定义一个枚举

typedefenum{

    SexMan,

    SexWoman

} Sex;

定义一个结构体

typedefstruct{

    intyear;

    intmonth;

    intday;

} Date;

17、@class只是告诉对象 这是一个类 , 但是不包含.h中的属性与方法

 1>@class只是告诉编译器某个名称是一个类,例如@class person仅仅告诉编译器person是一个类

2>开发中引用一个类的规范

在.h中用@class来声明

在.m中用import来包含类的声明

3>两端循环引用的解决方案

一端用retain一端用assign

在.h中用@class来声明可以解决循环包含的错误 

例如

#import

#import "Person.h"

@interfaceCar : NSObject

@property(nonatomic,retain)Person *p;

@end

#import

#import "Car.h"

@interfacePerson : NSObject

@property(nonatomic,retain)Car *car;

@end

这样会报错,编译不通过

#import

@classPerson;

@interfaceCar : NSObject

@property(nonatomic,retain)Person *p;

@end

#import

@classCar;

@interfacePerson : NSObject

@property(nonatomic,retain)Car *car;

@end

这样才不会报错,编译可以通过,然后在.m文件中用#import “”来包含头文件

这样做编译效率也比较高,如果按照第一种方式,一旦包含的类种的属性或者方法修改过了,就会造成每一个只要#import “”的.h都会重新编译一遍,造成效率比较低

18、autorelease的使用

autorelease方法会返回对象本身

autorelease 会把对象放在一个自动释放池中,当自动释放池被销毁的时候,会对池中的对象做一次release操作

    @autoreleasepool{

        Person *p =  [[[Person alloc]init]autorelease];

    }

会在池子结束的时候,对person对象调用一次release操作

autoreleasepool是可以嵌套使用的,而且autoreleasepool是放在栈内存中的,先进后出。

autoreleasepool的基本用法:

1>会将对象放入一个自动释放池中

2>当自动释放池销毁的时候,会对池中的对象进行一次release操作

3>会返回对象本身

4>调用完autorelease方法,对象的引用计数器不变,只有当autoreleasepool执行完毕之后,才会对池中的所有对象进行一次release操作

autorelease的好用:

1>不用关心对象释放的时间

2>不用关心什么调用对象的release

autorelease的使用注意:

1>占用较大内存的对象,不要随便的使用autorelease

2>占用较小内存的对象使用autorelease没有太大的影响

池子autoreleasepool的错误写法:

1>    @autoreleasepool{

        Person *p =  [[[[Person alloc]init]autorelease]autorelease];//调用两次autorelease会出现野指针错误

    }

2>    @autoreleasepool{

        Person *p =  [[[Person alloc]init]autorelease];

        [p release];

    }        也会出现也指针错误

3>        Person *p =  [[[Person alloc]init]autorelease];这样写没有任何的意义,因为autorelease不放到autoreleasepool中是不会调用release

自动释放池:

1>ios程序中也会创建自动释放池,这些自动释放池以栈的形式存在

2>当一个对象调用autorelease方法的时候,会将这个对象放到栈顶的释放池

自动释放池的创建方法:

#pragma mark ios5之前

    NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];

    Person *p =  [[[Person alloc]init]autorelease];

    [pool release];

#pragma mark ios5之后

    @autoreleasepool{

        Person *p =  [[[Person alloc]init]autorelease];

        [p release];

    }

}

19、

1>系统自带的方法没有alloc/new/copy,说明返回的对象都是autorelease的

例如  NSString *str =[NSString stringWithFormat:@"string"];

    NSString *str1 =[NSString stringWithString:@"string"];

2>开发中经常提供一些类方法快速创建一个已经autorelease的对象

创建对象的时候,不要直接用类名,要用self,以满足子类的需求

例如

+(id)person{

    return  [[[selfalloc]init]autorelease];

}

内存管理的总结:

一、计数器操作:

1>retain +1;

2>release -1;

3>retaincount  :获取计数器

二、set方法的内存管理

1>set的实现

-(void)setCar:(Car *)car{

    if(_car != car){

        [_car release];

        _car =[car retain];

    }

}

2>delloc方法的实现(不要直接调用delloc)

-(void)dealloc{

    [_car dealloc];

    [superdealloc];

}

三、property参数

oc对象:

@property(nonatomic,retain)类名*属性名;

非oc对象:

@property(nonatomic,assign)类型名称属性名;

四、@autoreleasepool

1、系统的方法中如果不带有alloc、new、copy,这些方法返回的对象都是已经autorelease过的

2、在开发过程中用类方法创建对象的时候,不要直接使用类名。可以用self(利用类方法快速创建一个autorelease对象)

ARC

ARC的判断准则:只要没有强指针指向对象,就会释放对象

1>ARC的特点是不允许调用retain/release/retainCount

2>允许重写delloc,但是不允许调用【super delloc】

3>property参数

*strong 成员变量是强指针 ,相当于之前retain(只适用于oc对象)

*weak成员变量是弱指针,相当于之前的assign(适用于oc对象)

*assign:适用于非oc对象

指针分为两种:

强指针:__strong 默认情况下就是强指针

弱指针:__weak  当弱指针指向的对象消失后,默认会指向nil

ARCMRC的转换

1>mrc项目 arc

xcode -> edit ->convert -> to object ARC

2>查看项目当前是否为 ARC

buildSetting ->搜索auto -> objectc automatic reference counting ->yes代表arc No代表mrc

3>将项目中某个文件改为 arc或者mrc

build phases ->compile source ->-fno-objc-arc不需要arc或者-f-objc-arc需要ARC

当两端循环引用的时候,解决的方案

1、ARC

一端用strong一端用weak

2、非arc

一端用retain一端用assign

Block:

intsum(inta,intb){

    returna+b;

}

-(void)viewDidLoad {

    [superviewDidLoad];

    int(*p)(int,int)= sum;

    intsum = p(10,12);

    NSLog(@"%d",sum);

}

指向函数的指针

int(^sumBlock)(int,int)=^(inta,intb){

        returna+b;

    };

    sumBlock(100,100);

1>如何定义block变量

Int(^SumBlock)(int,int);

void(^myBlock)();

2>如何利用block封装代码块

^(int a,int b){

return a-b

};

^(){

NSLog(@“111111”);

};

3>block访问外部变量

*block内部可以访问外面的变量

*默认情况下,block内部不能修改外面的变量

*给局部变量上加上__block关键字,这个局部变量才可以在block内部修改

4>利用typedef定义block类型

typedefint(^MyBlock)(int,int);

以后就可以利用MyBlock这种类型来定义block变量

协议Protocol

1>基本用途

*可以用来声明一大堆方法

*只要某各类遵守了这个协议,就相当于拥有了这个协议的所有方法

*只要父类遵守了某个协议,就相当于子类也遵守了

2>格式

@protocol协议名称

//协议方法

@end

某个类遵守某个协议

@interface类名:父类<协议名称1,协议名称2>

@end

3>关键字

@required:这个方法是必须实现的(若不实现,编译器会发出警告)

@optional这个方法不一定实现

4>协议遵守协议

*一个协议可以遵守其他多个协议,多个协议之间用逗号隔开

*一个协议遵守了其他协议,就相当于拥有了其他以协议中的方法声明

@protocol协议名称<协议1,协议2>

@end

5>基协议

*nsobject是一个基类,最根本最基础的类,热河其他类都要继承它

*其实还有一个协议,名字也叫NSobject,它是一个基协议,最根本的协议

*nsobject协议中声明很多最基本的方法,比如description、retain、release等

*建议每一个新协议都要遵守nsobject协议

6>定义一个变量的时候,限制这个变量保存的对象遵守某个协议

类名<协议名称>*变量名;

id<协议名称>变量名;

NSObject*object;

Idobj2;

如果没有遵守协议,编译器会报警

7>@propety中声明的属性也可以用作一个遵守协议的限制

@property(nonatoimic,strong)类名<协议名称>*属性名

8>协议可以定义在单独的.h中,也可以定义在某个类型中

*如果这个协议只用在某个类中,应该定义在该类中

*如果某个协议用在很多类中,就应该把协议定义在单独的文件中

9>分类可以定义在单独.h和.m文件中,也可以定义在原类中

1>一般情况下,都是定义在单独文件

2>定义在原类中的分类,只要求看懂语法

集合中的对象的内存管理

1>当对象被添加到集合中的时候,对象的引用计数器会加一

2>当集合被销毁的时候,会对集合中的对象发送一次release消息

3>当对象被移除的时候,也会给对象发送一次release消息

@property内存管理的策略

1非ARC

1>copy:只用于nsstring/block

2>retain:除nsstring/block以外的oc对象

3>assign:基本数据类型、枚举、结构体(非oc对象)当两个对象相互引用的时候,一端用retain一端用assign

2ARC

1>copy:只用于nsstring/block

2>strong:除nsstring/block以外的oc对象

3>assign:基本数据类型、枚举、结构体(非oc对象)

4>weak当两个对象相互引用的时候,一端用retain一端用assign

自定义类实现copy操作

1>类遵守NSCopying协议

2>实现-(id)copyWithZone:(nullableNSZone *)zone;方法

3>在- (id)copyWithZone:(nullableNSZone *)zone方法中创建一个新的对象,并设置该对象数据与现有对象一致,并返回该对象

单例模式

alloc方法其实调用的是allocWithZone

Static修饰局部变量,只创建一次

static修饰的全局变量,只有当前文件才可以访问,并且只创建一次

1>永远只分配一块内存来创建对象

2>提供一个类方法,返回内部唯一的一个对象

3>最好保证init方法也只初始化一次

Dispath_once方法是线程枷锁的,能保证线程安全

非ARC单例模式的实现比ARC单例模式的实现多了

-(id)retain{

}

-(NSUInteger)retainCount{

}

-(onewayvoid)release{


}

-(instancetype)autorelease{


}

// ## : 连接字符串和参数

#if __has_feature(objc_arc)判断编译环境是ARC还是MRC

#define singleton_h(name)+(instancetype)shared##name;

#if __has_feature(objc_arc)// ARC 

#define singleton_m(name)\

static id _instance;\

+(id)allocWithZone:(struct _NSZone *)zone \

{ \

    static dispatch_once_t onceToken;\

    dispatch_once(&onceToken,^{ \ dispatch_once线程安全,枷锁了

        _instance =[super allocWithZone:zone];\

    });\

    return _instance;\

} \

 \

+(instancetype)shared##name \

{ \

    static dispatch_once_t onceToken;\

    dispatch_once(&onceToken,^{ \

        _instance =[[self alloc]init];\

    });\

    return _instance;\

} \

+(id)copyWithZone:(struct _NSZone *)zone \

{ \

    return _instance;\

}

#else// ARC

#define singleton_m(name)\

static id _instance;\

+(id)allocWithZone:(struct _NSZone *)zone \

{ \

static dispatch_once_t onceToken;\

dispatch_once(&onceToken,^{ \

_instance =[super allocWithZone:zone];\

});\

return _instance;\

} \

\

+(instancetype)shared##name \

{ \

static dispatch_once_t onceToken;\

dispatch_once(&onceToken,^{ \

_instance =[[self alloc]init];\

});\

return _instance;\

} \

\

-(oneway void)release \

{ \

\

} \

\

-(id)autorelease \

{ \

return _instance;\

} \

\

-(id)retain \

{ \

return _instance;\

} \

\

-(NSUInteger)retainCount \

{ \

return 1;\

} \

\

+(id)copyWithZone:(struct _NSZone *)zone \

{ \

return _instance;\

}

#endif

控制器的生命周期

-(void)loadView{

    [superloadView];

}

-(void)viewDidLoad{

    [superviewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated{

    [superviewWillAppear:animated];

}

-(void)viewDidAppear:(BOOL)animated{

    [superviewDidAppear:animated];

}

-(void)viewWillDisappear:(BOOL)animated{

    [superviewWillDisappear:animated];

}

-(void)viewDidDisappear:(BOOL)animated{

    [superviewDidDisappear:animated];

}

-(void)viewWillUnload{

    [superviewWillUnload];

}

销毁view

-(void)viewDidUnload{

    [superviewDidUnload];

}

-(void)didReceiveMemoryWarning{

    [superdidReceiveMemoryWarning];

}

Block可以使用在定义之前声明的局部变量

    inti=10;

    void(^myBlock)(void)= ^(){

        NSLog(@"%d",i);

    };

    i = 100;

    myBlock();

打印的结果是 10;

1>在定义block的时候,会在block中建立当前局部变量的内容的副本(拷贝)

2>后续对该值进行修改不会影响block中的数值

3>如果需要在block中保持局部变量的数值变化,需要使用————block关键字

4>使用————block关键字之后,同样可以在block中修改变量的值

runtime

运行时机制:比较高级的特性,纯C语言

平时的oc代码——>C语言的运行时代码

默认情况下任何block的内存都是分配在栈中的,随时可能被回收。

对block进行一次copy操作就会把内存分配到堆中。

block会对代码块中的对象进行一次强引用,例如

self.block = ^{

self.age = 20;

}

这个时候,block会对self进行一次强引用,而block又是self的一个copy属性,也属于强引用,所以造成了循环引用;

因此当block中使用了对象的时候,需要判断是否造成了循环引用。如果造成了循环引用,就需要用——weak 来重新用指针指向对象

或者__unsafe_unretained  来重新修饰 

例如

__unsafe_unretainedPerson *p2 = p1;

    __weakPerson *p3 = p1;

    __weaktypeof(self)weakSelf =self;

    typeof(self) 就是用来判断类型,即等价于 self的类型*

KVC

利用kvc可以随意的修改一个对象的属性或者成员变量(并且私有的也可以)

Person *p1 =[[Person alloc]init];

    Dog *dog =[[Dog alloc]init];

    [p1.dog setValue:@"dogname" forKey:@"name"];

    [p1.dog setValue:@"dogname" forKeyPath:@"dog.name"];

人对象有一个狗的属性,狗又有name的属性;

    [p1.dog setValue:@"dogname" forKey:@"name”];中的key只能是属性名,否则会报错;

    [p1.dog setValue:@"dogname" forKeyPath:@"dog.name"];

可以是路径,又可以是属性名

forKeyPath包含了for的功能,以后用forkeyPath

iOS中的多线程

1>一个NSTread对象就代表一条线程

2>创建和启动线程

NSThread *thread =[[NSThread alloc]initWithTarget:selfselector:@selector(run:)object:@"hah"];

  [thread start];

3>主线程相关的用法

[NSThread mainThread];

[NSThread isMainThread];

 [thread isMainThread];

4>设置线程的优先级

    [NSThread threadPriority];查看当前线程的优先级

    [NSThread setThreadPriority:0.5];设置当前线程的优先级

5>设置线程的名字

    thread.name = @"线程一";

6>创建线程的时候就启动线程

 [NSThread detachNewThreadWithBlock:^{


    }];

    [NSThread detachNewThreadSelector:@selector(run:)toTarget:selfwithObject:@"哈哈"];

7>隐shi创建

    [selfperformSelectorInBackground:@selector(run:)withObject:@"哈哈”];

线程的状态

当线程在阻塞和死亡状态的时候,会退出可调度线程池中。但是内存还在。

线程状态的控制

最后的参数是说这个performSelector方法是否等待执行完毕,才继续跳出子线程操作

GCD

会自动帮我们创建线程

MRC中队列是需要释放的  当调用creat方法的时候,要调用dispatch_release(queue)方法去释放队列

在ios中凡是函数带有create、copy/new/retain等字眼,都需要在不需要使用这个数据的时候调用release操作

 CFArrayRef array = CFArrayCreate(0,0,11,0);

    CFRelease(array);在调用CF函数的时候,即使是在arc环境下也需要调用一下release操作

CF(core Facation)框架在ARC中也需要手动release

同步函数:

*串行队列:不开启新的线程,任务串行执行

*串行队列(主队列)会出现死锁

*并行队列:不开启新线程,任务串行执行

异步函数:

*串行队列 :开启一条新的线程,任务并行执行

*串行队列(主队列)不会开启新的线程

*并行队列: 开启新的线程,任务并行执行

    dispatch_queue_t mainqueue = dispatch_get_main_queue();

    dispatch_sync(mainqueue,^{

        NSLog(@"这样会死锁");

    });

dispatch_queue_t mainqueue = dispatch_get_main_queue();

    dispatch_async(mainqueue,^{

        NSLog(@"这样不会发生死锁");

    });

因为异步函数虽然也是放在了主线程中,但是比较特殊,会将block中的代码缓后执行,所以不会出现死锁

延迟执行:

第一GCD:

 //全局并发队列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    //计算执行任务的时间

    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3.0 * NSEC_PER_SEC));

    //when的这个时间点去执行queue的任务

    dispatch_after(when,queue,^{


    });

第二:

    [selfperformSelector:@selector(run:)withObject:@"hahha" afterDelay:3.0];

一次性代码

 staticdispatch_once_t onceToken;

    dispatch_once(&onceToken,^{


    });

#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)

#define main_queue dispatch_get_main_queue()

 dispatch_group_t group = dispatch_group_create();

    dispatch_group_async(group,global_queue,^{

        //下载图片1

    });

    dispatch_group_async(group,global_queue,^{

        //下载图片2

    });

    dispatch_group_notify(group,main_queue,^{

        //当任务一 任务二 完成之后,回到主线程中去操作

    });


NSOpertion:

多线程

1.NSThread

1> 开线程的几种方式

* 先创建,后启动

NSThread *thread =[[NSThread alloc]initWithTarget:selfselector:@selector(run)object:nil];

[thread start];

* 直接启动

[NSThread detachNewThreadSelector:@selector(run)toTarget:selfwithObject:nil];

[selfperformSelectorInBackground:@selector(run)withObject:nil];

2> 其他用法

NSThread *current =[NSThread currentThread];

+(NSThread *)mainThread;// 获得主线程

3> 线程间通信

performSelectorOnMainThread.....

2.GCD(重点)

1> 队列的类型

* 并发队列

获得全局的并发队列: dispatch_get_global_queue

* 串行队列

a.自己创建

dispatch_queue_create

b.主队列

dispatch_get_main_queue

2> 执行任务的方法类型

*同步(sync)执行

*异步(async)执行

3> 了解队列和方法的配合使用

4> 线程间通信

dispatch_async(

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

   // 执行耗时的异步操作...

   dispatch_async(dispatch_get_main_queue(),^{

       // 回到主线程,执行UI刷新操作

   });

});

5> 其他用法

dispatch_once

dispatch_after

dispatch_group_async\dispatch_group_notify

3.NSOperation

1> 基本使用

NSInvocationOperation

NSBlockOperation

2> NSOperationQueue(重点)

* 最大并发数设置

-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;

* 设置依赖(面试题)

[operationB addDependency:operationA];// 操作B依赖于操作A

3>自定义Operation(了解基本流程)

4> 如何解决一张图片(一个url)重复下载的问题(面试题)

你可能感兴趣的:(OC基础)