黑马程序员_arc编译特性和block数据类型,protocol协议

(一)arc编译特性:
acr:全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。它是一种编译器特性,基本使用了arc内存管理后,基本怎么写都不会出现内存泄露问题。
1.指针分类:
指针分类强指针和弱指针两种,当创建指针时,如什么都不写默认为弱指针。
①强指针:strong; 书写规范__strong 只有强指针指向的对象才算真正的在“使用”对象。如果没有强指针指向,对象就会被自动销毁。
②弱指针:weak;书写规范 __weak 弱指针无法决定对象是否被释放。
2.arc判断标准:只要没有强指针指向对象和,就会自动释放。只要弱指针对象被销毁,那么为了防止弱指针变成野指针造成内存泄露,此时弱指针自动nil清零。
3.@property参数的改变
由于arc中是无法使用诸如release,retain,dealloc,retainCount等关乎内存的对象方法的,所以在用@property定义成员变量时,参数会有变化。
①strong:表明成员变量是强指针 (用于OC对象)。
②weak:表明成员变量是弱指针 (用于OC对象)。
③assign:用于非OC对线,也就是基本数据类型。
④以前的一切不变,除了把retain改成strong。
4.arc依旧允许用户重写dealloc方法,但是不允许在使用super dealloc方法了。
(二)项目开发中arc和非arc混用:
①如果一个项目本来不是arc,但是想让这个.m使用arc,在项目管理的-build phases输入-f -objc -arc参数
②果一个项目本来是arc,但是想让这个.m不使用arc,在项目管理的-build phases输入-fno -objc -arc参数
(三)arc的循环引用:
和之前retain循环引用原理一样,这样会导致互相牵扯对方,无法完全释放内存。解决方法就是两端一端强指针一端弱指针。

(四)block数据类型:

1.作用:

block是一种数据类型,就像int,double,可以定义变量,到时候直接调用就可以实现block的使用。block的作用是用来保存/封装一端代码,类似定义函数。block可以在程序运行中保存一段代码。在OC语言学习和IOS开发中,block的使用非常频繁。
2.定义block
block可以有返回值,也可以传入形参,可以保存代码,并且调用方式和函数一样,不同的是用函数是用*p指针来指向的,而bolck的标志是^.定义规格:

①无参数无返回值:

 void (^myBlock)();


②有参数有返回值:

 double (^myBlock1)(double,double);

3.定义赋值block:

// 用一个block输出a条横线

    void (^printLineblock)(int) = ^(int a){

        while (a>0)

        {

            NSLog(@"-----");

            a--;

        }

    };

    printLineblock(5);


如上为打印a条横线。左边是block的定义,右边是传入参数类型(没有形参可以不写,甚至括号也可以省略)。整个{  }就是block封装的代码,最后直接调用定义好的变量,就可以完整block的调用,实现打印功能。

4.block访问外面变量

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


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


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


5.利用typedef定义block:

之前每一次使用block都要写很长一串。例如我们要定义对于两个数的加减乘除取余运算等等,这种变量定义,他们的返回值都是同类型的,传入的参数也是一样的,唯一不同的就是变量名称,回想起以前对 指向函数的指针进行typedef的方法,同时我们可以定义block:

    typedef int (^MyBlock)(int,int);

    

    int (^sumBlock)(int,int) = ^(int a,int b){

        return a+b;

    };

    int (^minusBlock)(int,int) = ^(int a,int b){

        return a-b;

    };

    MyBlock Muliply = ^(int a,int b){

        return a*b;

    };

    NSLog(@"%d---%d---%d",sumBlock(1,2),minusBlock(19,10),Muliply(10,10));



如上代码分析,先用复杂的方法定义了两个block,计算两个数字的加减。然后找到他们的共同点,都是传入参数,返回值类型一样。就可以teyedef创造一个MyBlock类型,然后用这个类型定义变量完成了两个数的乘法。以后block都应该进行typedef以保证代码的简洁性。

(五)protocol协议:

protocol是一种协议,用来声明一大堆方法。只要某个类或者某个协议遵守了协议,就相当于拥有了这个协议中所有方法的声明。

1.基本使用:


#import <Foundation/Foundation.h>

@protocol MyProtocol <NSObject>


- (void)tese2;


@required

- (void)tese1;


@optional

- (void)tese3;

- (void)tese4;


@end



①关键字@protocol @end :用来描述定义的方法声明。在这里只能写方法的声明,并不能定义成员变量。就像分类一样,只能对方法做文章。并且可以拥有两个关键字@required和@optional来修饰方法。
②required:默认方法为required,要求实现,不实现就会警告,不报错。
③optional:不要求实现。

所以在上面一共声明了4个方法,其中tese1,tese2是要求实现的。tese3,tese4不要求实现。

④<NSObject>:   <>是协议的标志,就像()预示着分类, : 预示着继承, ^是block数据类型一样。协议也可以遵守协议,如果一个协议遵守了另一个协议,那么这个协议就会拥有另一个协议的所有方法声明。<NSObject>就是一个基协议,最基本的协议,NSObject类是遵守<NSObject>协议的。所以一般所有的协议都会遵守NSObject基协议。当一个协议想要遵守另一个协议,就可以拥有这个协议的所有方法声明。代码如下:

#import <Foundation/Foundation.h>

@protocol MyPreotocol

@protocol MyPreotocol3 <MyPreotocol>

- (void)test3;

@end



如上代码,@protocol MyProtocol3 <MyProtocol> --->创建一个我的协议3,然后遵守我的协议,这样就拥有我的协议里面的tess1,2,3,4四个方法的声明。在每次遵守自定义协议的时候,都要对这个协议进行声明,告诉编译器这是一个协议。就像@class方法声明这是一个类对象一样,这样的方法可以使得性能更为优化。当然,单纯的#import 协议名称 也可以,但是这样的拷贝往往浪费性能。使用@protocol 要遵循的协议名  方法快速告诉编译器这是一个协议。但是仅仅是声明,此时协议里面有什么方法还都不知道。当真正想要用到协议方法时候再在.m文件中#import 要遵循的协议名 就可以导入协议方法了。下面我们创建一个类,完成类遵守MyProtocol协议:
Person.h:

#import <Foundation/Foundation.h>

@protocol MyProtocol;

@class Dog;


@interface Person : NSObject <MyProtocol>


@property (nonatomic,strong)Dog *dog;


@property (nonatomic,strong)id<MyProtocol> dog1;


@end



如上:Person.h中首先告诉编译器,MyProtocol是一个Protocol协议,Dog是一个class Dog类,然后Person类遵守<MyProtocol>协议,并且创建了一个狗对象成员变量和一个id类型的成员变量dog1。id是可以看成NSObject *的指针类型,所以不需要加*。

Person.m:

#import "Person.h"

#import "MyProtocol.h"


@implementation Person

- (void)tese1{

}

- (void)tese2{

}

@end



如上:在.m实现中要#import协议的.h文件以访问协议中的方法。然后对Myperotocl协议中@required的方法进行实现。(不实现会警告,但是不会报错)。此时一个类遵循协议的基本实现就能够完成了。


下面定义一个Student类继承Person。Student.h:

#import "Person.h"


@protocol StudentProtocol <NSObject>

- (void)StudentTest;


@end

@interface Student : Person<StudentProtocol>

- (void)selftTest;

@end



如上可以看出,协议是可以写在类里面的,并不是必须单独要放到一个.h文件中。协议写在了student类的.h中意味着只有这个类可以使用StudentPerorocol协议

Student.m:

#import "Student.h"

#import "MyProtocol.h"

@implementation Student


- (void)tese1{

}

- (void)tese2{

}

- (void)StudentTest{

}

- (void)selftTest{

}

@end



如上代码可以看到,继承是拥有父类的所有属性,所以协议也会继承,只需在.m文件中import协议的头文件就可以进行方法的实现。其实分类是也可以整个都写在一个类之中的。只不过如果分类方法很多,就应该放到一个新生成的.h.m中,如果分类很少,就应该直接放到@interface@end和@implementation和@end中去,不在需要多以此举再在类中创建一个分类了。所以这种方法用到的很少。
2.总结:
①定义
@protocol 协议名称 <NSObject>@end
②遵守协议
类遵守协议
@interface 类名 : 父类名 <协议名称1, 协议名称2>@end
协议遵守协议
@protocol 协议名称 <其他协议名称1, 其他协议名称2>@end

③方法声明关键字
@required (默认):要求实现,如果没有实现,会发出警告

@optional:不要求实现

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

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

id<协议名称> 变量名;

NSObject<MyProtocol> *obj;

id<MyProtocol> obj2;

如果没有遵守对应的协议,编译器会警告

⑤@property中声明的属性也可用做一个遵守协议的限制

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

@property (nonatomic, strong) id<协议名称> 属性名;

@property (nonatomic, strong) Dog<MyProtocol> *dog;

@property (nonatomic, strong) id<MyProtocol> dog2; 

⑥协议和分类都可以定义在单独.h文件中,也可用定义在某个类中。





















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值