[非凡程序员] 杨茹

IOS的内存管理

1.IOS中对于每一个对象都会有一个对象计数器


2.IOS内存管理分为三种(MRC:手动释放内存  autorelaese:自动释放内存 ARC:自动引用计数)

(1)MRC 黄金法则: 一旦对象被创建(new alloc init copy retain,那么就由创建者释放。总结:谁创建,谁释放,谁retain,谁release。其中 retain 计数器加一  release 计数器减一。

使用方式:Target-> 搜索auto -> 找到Automatic Reference Counting 将其修改成NO


如情况一


 //实例化Person对象 此时计数器为 1

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

    //计数器加一

    [person1 retain];

    //计数器减一

    [person1 release];

    //打印当前计数器的值

    NSLog(@"%li",[person1 retainCount]);


如情况二


 //若只是创建一个person的指针 则计数器为 0

    Person *person;

     // 因为计数器的release是针对于对象计数器而言的,此时没有对象,所以即使[person retain] 打印出的计数器的值永远为0

    


如情况三


 //创建了一个Dog对象

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


 //给人设置狗对象后,狗被引用一次 , 此时dogretainCount2

    [person1 setDog:dog];


//类的类属性,设置和获取,setget,现在可以简便化:

    //@property \ @synthesize

    //noatomic 高性能  atomic 低性能

    //retain 代表针对于这个对象计数器+1

    //readonly  代表对象只读

    //setter getter 更改这个方法的名字

    //assign 赋值通过针对于简单的数据类型



 //3.释放内存用dealloc,一般在.m文件中实现 [super dealloc],只要调用对象的release方法,就会进入dealloc;

    

//4.类的类属性,setget,现在可以简化为:@property @synthesize

    //noatomic 高性能  atomic 低性能 readonly  代表对象只读

    //setter getter 更改这个方法的名字

   

//5.有内存管理,用retain  OC语言的数据类型可内存管理

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

    

  无内存管理 assign  c语言的基础数据类型无内存管理

  // @property( nonatomic , assign ) int age;



3.关于retainCount1,-10,无穷大的条件

(1)1 是对象计数 当创建对象时或者对象即将释放时为1,即对象计数器最小为1.

(2)0 当一个指针的值为空时。

(3)为-1或无穷大时 当一个数据类型被赋值时。

不可变对象通常被称为静态常量,这类对象一般不能用于计数,而可变的对象是可以用来计数的



.浅拷贝和深拷贝

1.浅拷贝 copy 通常指针对于指针进行拷贝,特点为:通过多个指针指向同一片内存地址。

 NSString *string = @"123";

    NSString *stringI = [string copy];

这时stringstringI输出的内存地址相同

2.深拷贝 mutableCopy 指的是赋值内容并且重新创建一块内存地址

 NSString *stringII = [string mutableCopy];

这时stringstringII输出的内存地址不相同


.自动释放池(autorelease)

1.autorelease通常有作用域,当在作用域范围内的创建特定的对象时,出去作用域计数器就会-1

@autorelease{

    Person *personP = [[Person alloc]autorelease];

//特定的autorelease创建的对象才在出去作用域的时候release 计数器 -1

此时也可以在作用域里面对person retainrelease,但是不管怎样,出作用域时计数器只会减一

}


.ARC(自动引用计数)

1.ARC会追踪你的对象并决定哪一个仍会使用而哪一个不 会再用到

如果启用了ARC,编译器会自动插入retainrelease 语句

通过Xcode启用或禁用可

2.ARC的特点

(1)不允许调用release,retain,retainCount    

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

(3)@property的参数:  

  • strong:相当于原来的retain(适用于OC对象),成员变量是强指针   

  • weak:相当于原来的assign,(适用于OC对象类型),成员变量是弱指针   

  • assign:适用于非OC对象类型(基础类型)

相互引用时注意的问题:

1.在一方的.h文件中要导入另一方的头文件,另一方的.h文件要引用@class name

 #import <Foundation/Foundation.h>

   #import "MicroBlog.h"

   @interface Person : NSObject

   #import <Foundation/Foundation.h>

   @class Person;

   @interface MicroBlog : NSObject

2.一方使用强指针,另一方使用弱指针

3.引用@class的一方若要在.m文件中实现相应的方法,要在.m文件中再次导入另一方的头文件

 #import "MicroBlog.h"

   #import "Person.h"

   @implementation MicroBlog


ARC实例:

person.h


#import <Foundation/Foundation.h>

#import "MicroBlog.h"


@interface Person : NSObject

@property (nonatomic ,strong)MicroBlog *microBlog;

@property (nonatomic,strong) NSString *name;

@property (nonatomic,weak) NSString *comment;

-(void)printf;

@end



person.m

#import "Person.h"


@implementation Person

-(void)printf

{

    NSLog(@"%@%@发布了第%i条微博,内容是:%@",_name, [_microBlog time],[_microBlog second],[_microBlog content]);

}

@end


microBlog.h


#import <Foundation/Foundation.h>

@class Person;


@interface MicroBlog : NSObject

@property(nonatomic,weak) Person *person;

@property(nonatomic,weak) Person *commentPerson;

@property(nonatomic,weak) NSString *content;

@property(nonatomic,weak) NSString *time;

@property(nonatomic,assign) int second;


-(void)printComment;

@end


microBlog.m


#import "MicroBlog.h"

#import "Person.h"


@implementation MicroBlog

-(void)printComment

{

    NSLog(@"%@评论了你的微博:%@",[_commentPerson name],[_commentPerson comment]);

}

@end



main.m


#import <Foundation/Foundation.h>

#import "MicroBlog.h"

#import "Person.h"


int main(int argc, const char * argv[]) {

    

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

    person.name = @"小明";

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

    personI.name = @"小花";

    personI.comment = @"";

    

    MicroBlog *microBlog = [[MicroBlog alloc]init];

    

    microBlog.content = @"暑假去旅游";

    

    microBlog.second = 2;

    

    NSDate *date = [NSDate date];

    NSDateFormatter *dateformatter = [[NSDateFormatter alloc]init];

    [dateformatter setDateFormat:@"yyyy-MM-dd HH-mm-ss"];

    NSString *nowTime = [dateformatter stringFromDate:date];

    microBlog.time = nowTime;

    

    microBlog.commentPerson = personI;


   //这是容易忘记的一步,要给person对象设置microBlog

    person.microBlog = microBlog;

    

    [person printf];

    [microBlog printComment];

    

 return 0;

}




  KVC: key value coding 键值编码。


可以将对象属性变为一个键从而去设置属性的值
.KVC的四种方法

1.setValue:forKey: 设置类属性的值
: [hunter setValue:"光头强" forKey:"name"];

2.valueForKey: 取相对应的属性的值
: [person valueForKey:@"name"]

3.setValue:forKeyPath: 根据键路径设置类属性的值

4.valueForKeyPath: 根据键路径取相对应的属性的值(对象属性是另一个的类属性)
: [person valueForKeyPath:@"hunterPig.weight"]

.KVC中常用的几种计算方式
:
//创建森林对象
Forest *forest = [[Forest alloc]init];
//把三只猪放到同一个数组中
NSArray *array = [boarI,boarIII,boarII,boarII];

//将存放猪的数组放入到森林数组(是森里类的一个属性) 即完成了

[forest setValue:array forKey:"forestArray"];

1.count: 计算数量

//求猪的个数

NSLog("猪的个数是:%",[forest valueForKeyPath:"forestArray.@count"])

2.max: 计算最大值

//求猪重量的最大值

NSLog("猪的重量的最大值是:%",[forest valueForKeyPath:"[email protected]"]);

3.min: 计算最小值

//求猪重量的最小值

NSLog("猪的重量的最小值是:%",[forest valueForKeyPath:"[email protected]"]);

4.sum: 计算总和

//求猪重量的总和

NSLog("猪的重量的总值是:%",[forest valueForKeyPath:"[email protected]"]);

5.avg: 计算平均值

//求猪重量的平均值

NSLog("猪的重量的平均值是:%",[forest valueForKeyPath:"[email protected]"]);

.针对数组
1.
自动去除数组重复的元素  distinctUnionOfObjects

NSArray *arr = [1,@2,@3,@2];

NSLog("数组里的元素有%@",[arr valueForKeyPath:"@distinctUnionOfObjects.self"]);

2. 不会自动去除数组多余的元素 @unionOfObjects

  NSLog(@"数组里的元素有%@",[arrvalueForKeyPath:@"@unionOfObjects.self"]);



KVO: key value observing 当类属性的值发生改变时,会自动调用监听回调方法进行提醒


:KVO中必有的三种方法
1.给对象添加监听者 
[被监听者 addObserver:监听者 forKeyPath:@“类属性” options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
注意:被监听者和监听者可以是同一类实例化出的两个相同或不同的对象,也可以是不同类分别实例化出的对象
类属性可以是自己类的属性,也可以是对象类属性里面的属性

2.给对象移除监听者 
[被监听者 removeObserver:监听者 forKeyPath:@"类属性"];

3.一旦类属性的值发生改变,监听回调以下方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
其中的四个属性:
keyPath :监听的key
object: 监听的对象 
change: 返回新值和旧值(在添加监听者时需要设置)
context:上下文内容

它们的输出方式为:
NSLog("keyPath :%",keyPath);
NSLog("object :%",[object valueForKey:类属性”]);

NSLog("change :%",change);

取出旧值:[change valueForKey:“old”];
取出新值:[change valueForKey:@“new”];

类属性值发生改变时是发生在添加和移除监听者之间的


举例说明KVO

人监听账户里的账户名和账户余额属性

main.m


#import <Foundation/Foundation.h>

#import "Person.h"

#import "Account.h"


int main(int argc, const char * argv[]) {

    

    //实例化person对象

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

    

    //实例化一个账户

    Account *account = [[Account alloc]init];

    

    //给账户设置余额和账户名

    [account setValue:@"200" forKey:@"money"];

    [account setValue:@"123456" forKey:@"name"];

    

    //给账户添加监听者来监听它的余额

    [account addObserver:person forKeyPath:@"money" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

    

    //给账户添加监听者来监听它的zhanghum

    [account addObserver:person forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];


    

    //给账户重新设置余额和账户名

    [account setValue:@"500" forKey:@"money"];

    [account setValue:@"678954" forKey:@"name"];


    //移除监听者

    [account removeObserver:person forKeyPath:@"money"];

    [account removeObserver:person forKeyPath:@"name"];


    return 0;

}


person.m


#import "Person.h"


@implementation Person

//一旦被监听者的属性值发生改变,立即进入此方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{

//    NSLog(@"keyPath :%@",keyPath);

//    NSLog(@"object :%@",[object valueForKey:@"money"]);

//    NSLog(@"change :%@",change);

    

    //当同时监听对象的多个属性时,输出改变值时需要进行判断

    if ([keyPath isEqualToString:@"money"]) {

        

        NSLog(@"您的账户余额发生改变,当前金额为%@",[object valueForKey:keyPath]);

        

      NSLog(@"您当前余额总共有%i",[[change valueForKey:@"old"]intValue] + [[change valueForKey:@"new"]intValue]);

    }

    else

        if ([keyPath isEqualToString:@"name"]) {

            NSLog(@"您的账户名发生改变,当前账户名为:%@",[object valueForKey:keyPath]);

        }

     

}


@end


你可能感兴趣的:([非凡程序员] 杨茹)