黑马程序员_OC学习之内存管理

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


前言:OC中凡是手动建立的对象都需要我们自己管理内存,这些对象被分配到堆中。每个对象都有自己的引用计数器,如果计数器变为0,那么对象就被销毁,下面是OC中一系列关于内存方面的知识总结。


一、内存管理:

关于内存方面有几个关键词:1、retain、copy:使对象引用计数器加一;

2、release:释放一次,引用计数器减一;

3、alloc:创建新对象,默认引用技术器为一;

4、dealloc方法:当对象消亡时,会调用该方法。

例如:

<span style="font-size:18px;">#import <Foundation/Foundation.h>

@interface Person : NSObject

@end

@implementation Person

- (void)dealloc {
    NSLog(@"Person dead");  //当对象消亡,会调用这个方法
    
    [super dealloc];
}

@end


int main() {
    
    Person *p = [[Person alloc]init];   //这时p这个指针指向的对象默认引用计数器+1;
    [p retain]; //p指向的对象引用计数器+1
    
    [p release];    //计数器-1
    [p release];    //当p指向的对象计数器为0时,对象消亡;
    
    
    return 0;
    
}</span>


----------------------------------------------------------------------------------------------------------------------------------------------------------

二、@property参数:


先看一段代码:


<span style="font-size:18px;">#import <Foundation/Foundation.h>

@interface Dog : NSObject

@end

@interface Person : NSObject
{
    Dog *_dog;
}
- (void)setDog:(Dog *)dog;
@end

@implementation Person

- (void)dealloc {
    
    [_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
    NSLog(@"Person dead");  //当对象消亡,会调用这个方法
    
    [super dealloc];
}

- (void)setDog:(Dog *)dog {
    
    if (dog != _dog) {  //如果这条狗不是新领养的那一条
        
        [_dog release]; //对原来那条释放
        
        _dog = [dog retain];    //再对新狗保留所有权
        
    }
}

@end

@implementation Dog

- (void)dealloc {
    NSLog(@"Dog dead");
    
    [super dealloc];
}

@end


int main() {
    
    Person *p = [[Person alloc]init];   //这时p这个指针指向的对象默认引用计数器+1;
    Dog *d1 = [[Dog alloc]init];
    Dog *d2 = [[Dog alloc]init];
    
    p.dog = d1; //当人第一次养狗时,需要retain一下,意味获取狗的所有权。
    
    p.dog = d2; //人换了一条狗,那么就需要对原来那条狗释放
    
    [d2 release];
    [d1 release];
    [p release];    //当p指向的对象计数器为0时,对象消亡;
    
    
    return 0;
    
}</span>


根据例子我们知道,为了程序的严谨,我们会在set方法中加入一些代码,防止内存泄露。为了节省时间,可以为@property添加几个参数:


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

retain:release旧值,retain新值(适用于OC对象类型)

assign:直接赋值(默认。适用于非OC对象类型)

copy:release旧值,copy新值


2、是否生成set方法

readwrite:同时生成setter和getter的声明、实现

readonly:只会生成getter的声明、实现


3、多线程管理

nonatomic:无原子操作,性能高

atomic:原子操作,保证数据正确,性能低(默认)


4、setter和getter方法的名称

setter:决定了set方法的名称,一定要有冒号:

getter:决定了get方法的名称(一般用在BOOL类型)


5、ARC补充(在下面做介绍)

strong:强指针,替换retain

weak:弱指针,相当于assign,但用于OC对象


例如:


<span style="font-size:18px;">#import <Foundation/Foundation.h>

@interface Dog : NSObject

@end

@interface Person : NSObject

@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end

@implementation Person

- (void)dealloc {
    
    [_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
    NSLog(@"Person dead");  //当对象消亡,会调用这个方法
    
    [super dealloc];
}

@end

@implementation Dog

- (void)dealloc {
    NSLog(@"Dog dead");
    
    [super dealloc];
}

@end


int main() {
    
    Person *p = [[Person alloc]init];
    Dog *d1 = [[Dog alloc]init];
    Dog *d2 = [[Dog alloc]init];
    
    p.dog = d1;
    
    p.dog = d2;
    
    [d2 release];
    [d1 release];
    [p release];
    
    
    return 0;
    
}</span>


----------------------------------------------------------------------------------------------------------------------------------------------------------


三、循环引用:


当两个对象A包含B,B包含A时会引发循环引用,谁也不会被销毁,这时我们需要对其中一个做assign,另一个做retain


例如:


<span style="font-size:18px;">#import <Foundation/Foundation.h>

@class Person;   //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,assign) Person *person;
@end

@interface Person : NSObject
@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end

@implementation Person

- (void)dealloc {
    
    [_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
    NSLog(@"Person dead");  //当对象消亡,会调用这个方法
    
    [super dealloc];
}

@end

@implementation Dog

- (void)dealloc {
    
    NSLog(@"Dog dead");
    
    [super dealloc];
}

@end


int main() {
    
    Person *p = [[Person alloc]init];
    Dog *d = [[Dog alloc]init];
    
    p.dog = d;
    d.person = p;
    
    [d release];
    [p release];
    
    
    return 0;
    
}</span>


----------------------------------------------------------------------------------------------------------------------------------------------------------


四、autorelease:


OC会在程序运行时创建若干个自动释放池,并把它们放到一个栈中,我们可以把一个对象放到其中,当用在对象后加上autorelease时,代表它会把该对象放到栈顶的池子中。随着一个自动释放池被销毁,它会将它里面的对象做一次release操作。


例如:


<span style="font-size:18px;">#import <Foundation/Foundation.h>

@class Person;   //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,assign) Person *person;
@end

@interface Person : NSObject
@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end

@implementation Person

- (void)dealloc {
    
    [_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
    NSLog(@"Person dead");  //当对象消亡,会调用这个方法
    
    [super dealloc];
}

@end

@implementation Dog

- (void)dealloc {
    
    NSLog(@"Dog dead");
    
    [super dealloc];
}

@end


int main() {
    
    @autoreleasepool {
        
        Person *p = [[[Person alloc]init]autorelease];
        Dog *d = [[[Dog alloc]init]autorelease];
        
        p.dog = d;
        d.person = p;
    }   //当池子被销毁,里面的对象会做一次release操作
    
//    [d release];  //不需要release,因为我们d与p两个对象都在自动释放池中
//    [p release];
    
    
    return 0;
    
}
</span>

注意:当我们想准确操作一个对象的“生死”时,不要把它放到自动释放池中,它只适用于小数据的自动释放。


----------------------------------------------------------------------------------------------------------------------------------------------------------


五、ARC机制:(Automatic Reference Counting)


ARC属于编译时的机制,它会检查一个对象是否有强指针指向它,如果没有,它会在后面加上release代码。这点区分于JAVA的垃圾回收机制,JAVA程序会在程序运行时检测一个对象是否有指针指向,如果没有那么就会将对象作为垃圾回收。


解释一下@property中两个参数:


1、strong:声明对象为强指针(默认)


2、weak:声明对象为弱指针,当它指向的一个对象,同时没有其他强指针指向时,会被ARC添加release代码,该对象会被回收,这个弱指针也会自动被赋值为nil,所以弱指针不能单独指向对象。


例如:


<span style="font-size:18px;">#import <Foundation/Foundation.h>

@class Person;   //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,strong) Person *person;    //retain变为strong
@end

@interface Person : NSObject
@property (nonatomic, weak) Dog *dog; //防止循环引用,assign变成weak
@end

@implementation Person

- (void)dealloc {
    
    NSLog(@"Person dead");

}

@end

@implementation Dog

- (void)dealloc {
    
    NSLog(@"Dog dead");
//    [super dealloc ];   //这句会被报错
}

@end


int main() {
    
        
    Person *p = [[[Person alloc]init]autorelease];
    Dog *d = [[[Dog alloc]init]autorelease];
    
    p.dog = d;
    d.person = p;
    
//    [p release];    //有了ARC,所有关于内存方面的关键字都不会再被使用。
//    [d release];
    
    return 0;
    
}</span>

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tim_oc1init和tim_oc2init是STM32的定时器模块中的函数,用于初始化定时器的输出比较通道1和通道2。其中,tim_oc1init用于初始化通道1,tim_oc2init用于初始化通道2。这两个函数可以设置定时器的输出模式、极性、预分频器等参数,以满足不同的应用需求。 ### 回答2: tim_oc1init和tim_oc2init是两个函数,是在STM32开发中使用的定时器输出比较功能函数。 首先,我们需要了解一下定时器和定时器输出比较的概念。定时器是一种可编程、周期性的计时器,它能够在一定时间内产生定时中断或输出PWM信号。而定时器输出比较是指定时器对比较值进行比较,当定时器计数器计数值达到比较值时,定时器输出会发生变化。 tim_oc1init和tim_oc2init是用于设定定时器输出比较功能的函数,以tim_oc1init函数为例,它的具体功能包括: 1. 设定TIMx_CH1的输出模式和极性,可以选择PWM模式或脉冲模式,并可设定输出极性为正常或反转; 2. 设定比较值,即当计数器的值达到此值时触发输出; 3. 设定预分频系数和重载值,确定计时器的计数范围。 通过tim_oc1init和tim_oc2init函数的设定,可以实现定时器输出比较功能,可以控制各种电子设备的输出信号和开关控制,适用于各种行业的应用场景。在开发中,根据具体需求使用不同的输出模式和比较值,可以实现多种不同的功能操作。 ### 回答3: tim_oc1init和tim_oc2init是针对定时器的两个初始化函数。 首先,定时器是嵌入式系统中非常重要的一个模块,它可以通过计时和计数等方式实现各种定时和计时功能,比如控制LED灯闪烁、通过定时触发中断来完成一些任务等。 而tim_oc1init和tim_oc2init则是针对定时器的输出比较功能而设置的两个初始化函数,用于配置定时器的输出比较通道1和通道2。 对于tim_oc1init而言,它可以设置如下几个参数:定时器的指针、比较输出模式、预分频系数、占空比等。其中,比较输出模式有四种模式可供选择,分别为TIM_OCMode_Timing(定时模式)、TIM_OCMode_Active(有效电平模式)、TIM_OCMode_Inactive(无效电平模式)和TIM_OCMode_PWM1(脉冲宽度调制模式)。 而tim_oc2init则是针对定时器的输出比较通道2进行初始化,可以设置的参数与tim_oc1init相同,只不过它是控制通道2的输出状态。 需要注意的是,这两个函数都是基于STM32的定时器模块设计的,因此在使用它们时需要根据硬件平台来确定具体的实现方法和参数设置。 总的来说,tim_oc1init和tim_oc2init是非常重要的定时器初始化函数,可以方便地控制定时器的输出比较通道,从而实现各种自定义的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值