黑马程序员-ARC,Block与protocol

本文深入探讨了ASP.Net与Unity的开发技巧,并提供了.NET培训的资源,分享了ARC(自动引用计数)的概念及其在Objective-C中的应用,包括强指针与弱指针的区别、循环引用解决方法、Block封装代码与协议设计模式的运用,以及如何在项目中使用ARC与非ARC代码混用的技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

Arc(Atuomatic Reference Counting

(自动化的  引用  计数)

1,基本简介

ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入

适当的retain、release、autorelease语句。你不再需要担心内存管理,因为编译器为你处理了一切

 

ARC 是编译器特性,而不是 iOS 运行时特性,它也不是类似于其它语言中的垃圾收集器。因此 ARC 和手动内存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化

 

2,ARC的判断准则:只要没有强指针指向对象,就会释放对象。只要还有一个强指针变量指向对象,对象就会保持在内存中

 

3.  强指针和弱指针

 

强指针:默认情况下所有指针都是Strong指针 __strong两个下划线)

   

弱指针:指向的对象被回收后,弱指针会自动变为nil指针,不会引发野指针错误 __weak;

 

4.ARC特点

 

 1> 不允许调用release、retain、retainCount

 

 2> 允许重写dealloc,但是不允许调用[super dealloc]

 

 3> @property的参数

 

  * strong :成员变量是强指针(适用于OC对象类型)想长期拥有某个对象,应该用strong

 

  * weak :成员变量是弱指针(适用于OC对象类型)其他对象用weak。

 

  * assign : 适用于非OC对象类型

 

 4>以前的retain改为用strong,其他一切不变

 

 

代码示例:

 

@interface Person : NSObject

 

@property (nonatomic, strong) Dog *dog;//strong相当于retain

@property (nonatomic, weak)   Dog *dog;//

 

@end

 

int main()

{

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

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

   

    p.dog = d;

    d  = nil;

     

    NSLog(@"%@", p);//当strong的时候狗p还在,weak就消除了

    return 0;

}

void test()

{

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

    /* __weak Person *p = [[Person alloc] init];

   

       弱指针自动释放

    NSLog(@"%@", p);//输出是NULL

    */

   

    __weak Person *p2 = p;

      

    p = nil;//这行自动释放对象内存

   

    p2 = nil;

 

    NSLog(@"----");

 

}

 

Xcode的ARC转换功能

Edit里面的Refactor(重构)里面的Convert(转换) to Object-C ARC

 

怎样查看项目是不是ARC呢?

点击项目,Bulid Settings,然后搜索Auto,出现 Object-C ARC后面是Yes

 

当我们使用第三方框架的时候,非ARC的release报错,怎样既可以有ARC又有非ARC呢

Bulid Phases/Compile Sources/想使用非ARC的项目文件,然后双击或者回车。输入-fno-objc-arc

使用ARC的命令:-f-objc-arc

 

循环引用

 

两端互相引用时,

1》 ARC

 

一端用strong、一端用weak

 

2》非ARC

 

一端用retain、一端用assign

 

@interface Person :NSObject

 

//@peroperty (nonatomic, strong) Dog *dog;

@peroperty (nonatomic, weak) Dog *dog;

@end

 

@implementation Person

 

-(void)dealloc

{

    NSLog(@"Person is dealloc");

}

 

@end

 

@interface Dog :NSObject

 

@peroperty (nonatomic, strong) Person *person;

 

@end

 

@implementation Dog

 

-(void)dealloc

{

    NSLog(@"Dog is dealloc");

}

@end

 

 

int main()

{

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

 

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

    p.dog = d;

    d.person = p;

   

    return 0;

}

 

Block

 

Block封装了一段代码,可以在任何时候执行(程序运行时进行)

 

/*

block需要掌握:

 

1> 如何定义Block变量

int (^sumBlock)(int, int);

void (^myBlock)();

 

2> 如何利用Block封装代码

 

^(int a, int b){

   return a - b;

}

 

^() {

   NSLog();

}

 

^ {

   NSLog();

}

 

3> block访问外面变量

 

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

 

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

 

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

 

4》利用typedef定义block类型

typedef int (^myBlock)(int,int);

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

 

MyBlock b1;

b1 = ^(int a, int b){

   return a - b;

}

MyBlock b1,b2;

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

   return a - b;

};//千万不要忘记写分号,赋值语句后面要写。

*/

//typedef int (*SumP)(int, int);

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

int main()

{

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

    //int (*p2)(int, int) = sum;

    //SumP p = sum;

   

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

       return a + b;

    }

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

       return a - b;

    }

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

       return a * b;

    }

      

    // MyBlock() 典型的错误,MyBlock是类型,不是变量

  

    return 0;

}

//没有返回值。没有形参的block

void test()

{

   

    // block 用来保存一段代码,是个数据类型

    // block的标志:^

    /*

   block跟函数很像:

   1,可以保存代码

   2. 有返回值

   3. 有形参

   4.调用方式一样

   */

   

   // 定义block变量,如果block没有形参,可以省略后面的()

    void (^myblock)() = ^{

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

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

    }

 

    //利用block变量调用block内部代码

    myblock();

 

//有返回值。有形参的block

 

void test2()

{

    /*

       //指向函数的指针

   

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

       int d = p(10,20);

       NSLog(@"%d", d);

    */

 

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

       return a + b;

    }

   

    int c = sumblock(10,11);

   

    NSLog(@"%d",c);

 

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

   

    void (^lineBlock)(int) = ^(int n)

    {

       for (int i=0; i<n; i++)

       {

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

       }  

    }

 

    int d = lineBlock(5);

}

 

void test3()

{

    int a =10;

    __block int b =20;

   

    void (^block)();

    block = ^{

 

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

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

       // a = 20;

          

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

       b = 25;

    }

 

Protocol(协议)

1.基本用途

可以用来声明一大堆方法(不能声明成员变量

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

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

 

// :  继承

// <> 遵守协议

 

@protocol MyProtocol2;

@protocol MyProtocol3;

 

@interface Person : NSObject<Myprotocol,Myprotoco2>

// 继承是单继承,一个协议可以遵守其他多个协议。

 

@property (nonatomic, strong) id<Myprotocol2> obj;

 

// @property (nonatomic, strong) Hashiqi *dog;如同这句要有哈士奇狗,必须import头文件。所以要声明个@class Hashiqi,我们用协议也用类似的声明,避免COPY大量头文件

@end

 

@implementation Person

 

 

- (void)test

{

 

}

 

- (void)test2

{

 

}

 

- (void)haha1

{

 

}

- (void)hehe

{

 

}

@end

 

 

#import "MyProtocol2"

 

@interface Dog :NSObject <MyProtocol2>

 

@end

 

@implementation Dog

 

@end

 

@interface HaShiQi: Dog

 

@end

 

@implementation HaShiQi

 

@end

 

@protocol Myprotocol <NSObject>

//required ,optional在大多数情况下,用途在于程序员之间的交流

 

- (void)test3;//默认是required

 

@required// 要求实现,不实现就会发出警告

- (void)test;

 

@optional// 可选,不要求必须实现

- (void)test2;

 

@end

 

@protocol Myprotocol2 <NSObject>

 

- (void)haha1;

 

@optional

- (void)haha2;

 

@end

 

#import "MyProtocol.h"

 

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

@protocol MyProtocol3 <MyProtocol>

 

- (void)hehe;

 

@end

 

NSObject是一个基协议,最根本最基本的协议,他声明在Foundation框架里。

NSObject协议中声明很多最基本的方法,比如description、retain、release等。建议每个新的协议都要遵守NSObject协议

 

#import "MyProtocol.h"

#import "Person.h"

int main()

{

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

    p.obj = [[Dog alloc] init];

    p.obj = [[HaShiQi alloc] init];

    return 0;

}

 

void (test)

{

       NSObject *obj = @"l564sd";//多态,父类指针指向子类对象

   

    // 要求obj3保存的对象必须是遵守MyProtocol这个协议的

    /*NSObject<MyProtocol> *obj2 = [[NSObject alloc] init];这句话是错误的,因为前面是遵守协议的,后面的NSObject对象是不遵守MyProtocol协议的。这是不允许的*/

 

    NSObject<MyProtocol> *obj2 = [[Person alloc] init];

    obj2 = nil;

   

    id<MyProtocol> *obj3 = [[Person alloc] init];

    obj3 = nil;// 假如没有这句会有一个指针未使用的警告,但是不是上面类型错误了。

   

    // 要求obj4,保存的对象必须遵守MyProtocol3.并且继承了Person

    Person<MyProtocol3> *obj4 = [[Person alloc] init];

}

协议的总结

 1.协议的定义

 @protocol 协议名称 <NSObject>

  // 方法声明列表....

 @end

 

 2.如何遵守协议

 1> 类遵守协议

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

 

 @end

 

 2> 协议遵守协议

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

 

 @end

 

 3.协议中方法声明的关键字

 1> @required (默认)

   要求实现,如果没有实现,会发出警告

 

 2> @optional

   不要求实现,怎样不会有警告

 

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

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

 id<协议名称> 变量名;

 NSObject<MyProtocol> *obj;

 id<MyProtocol> obj2;

 

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

 

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

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

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

 

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

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

 

 6.协议可用定义在单独.h文件中,也可用定义在某个类中

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

 

 2> 如果这个协议用在很多类中,就应该定义在单独文件中

 

 7.分类可用定义在单独.h和.m文件中,也可用定义在原来类中

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

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

 

代理设计模式

设计原理

 

有些麻烦的事情不想自己亲自做,就可以找个人帮忙做,即交给代理对象去做

设计原则

 

首先得拥有某个代理对象属性

其次要很清楚代理有哪些方法

最后要保证能解耦

 

实现方案

定义一个protocol,在其中声明一些和代理沟通的方法

拥有一个代理属性id<protocol> delegate

让代理遵守protocol

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看: www.itheima.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值