iOS开发篇-内存管理(上)

简介: 现在iOS开发已经是ARC甚至是swift的时代,但是内存管理仍是一个重点关注的问题,如果只知盲目开发而不知个中原理,踩坑就跳不出来了,理解好内存管理,能让我们写出更有质量的代码。

现在iOS开发已经是ARC甚至是swift的时代,但是内存管理仍是一个重点关注的问题,如果只知盲目开发而不知个中原理,踩坑就跳不出来了,理解好内存管理,能让我们写出更有质量的代码。


内存管理是程序设计中很重要的一部分,程序在运行的过程中消耗内存,运行结束后释放占用的内存。如果程序运行时一直分配内存而不及时释放无用的内存,会造成这样的后果:程序占用的内存越来越大,直至内存消耗殚尽,程序因无内存可用导致崩溃,这样的情况我们称之为内存泄漏


ObjC的内存管理比较简洁,然而要深刻理解也不是一件易事,本文将介绍如何使用ObjC进行内存管理。


1. 引用计数


在ObjC中,对象什么时候会释放(或者对象占用的内存什么时候会被回收利用)?


答案:当对象没有被任何变量引用(也可以说是没有指针指向该对象)的时候,就会被释放。


那怎么知道对象已经没有被引用了呢?


ObjC采用引用计数(reference counting)的技术进行管理:


  • 每个对象都有一个关联的整数,称为引用计数器


  • 当代码需要使用该对象时,则将对象的引用技术加1


  • 当代码结束使用该对象时,则将对象的引用技术减1


  • 当引用计数的值变为0时,表示对象没有被任何代码使用,此时对象将被释放


与之对应的消息发送方法如下:


  • 当对象被创建(通过allocnewcopy等方法)时,其引用计数初始值为1


  • 给对象发送retain消息,其引用计数加1


  • 当对象引用计数归0时,ObjC给对象发送dealloc消息销毁对象


下面通过一个简单的例子来说明:


场景:有一个宠物中心(内存):可以派出小动物(对象)陪小朋友们玩耍(对象引用者),现在xiaoming想和小狗一起玩耍。


新建Dog类,重写其创建和销毁的方法:

//
//  Dog.m
//  TextARC
//
//  Created by taobaichi on 2017/3/27.
//  Copyright © 2017年 MaChao. All rights reserved.
//
#import "Dog.h"
@implementation Dog
-(instancetype)init{
    if (self = [super init]) {
        NSLog(@"小狗被派出去啦");
    }
    return self;
}
-(void)dealloc{
    NSLog(@"小狗回到宠物中心");
    [super dealloc];
}
@end


在main方法中创建dog对象,给dog发送消息

//
//  main.m
//  TextARC
//
//  Created by taobaichi on 2017/3/27.
//  Copyright © 2017年 MaChao. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog * dog = [[Dog alloc]init];
        //模拟:xiaoming需要和小狗玩耍,需要将其引用计数加1
        [dog retain];
        NSLog(@"小狗的引用计数为 %ld",dog.retainCount);
        //模拟:xiaoming不和小狗玩耍了,需要将其引用计数减1
        [dog release];
        NSLog(@"小狗的引用计数为 %ld",dog.retainCount);
        //没人需要和小狗玩耍了,将其引用计数减1
        [dog release];
        //将其指针置为nil,否则变成野指针
        dog = nil;
    }
    return 0;
}


输出结果为

2017-03-27 11:10:21.017977 TextARC[2645:84069] 小狗被派出去啦! 初始引用计数为 1
2017-03-27 11:10:21.018125 TextARC[2645:84069] 小狗的引用计数为 2
2017-03-27 11:10:21.018145 TextARC[2645:84069] 小狗的引用计数为 1
2017-03-27 11:10:21.018159 TextARC[2645:84069] 小狗回到宠物中心


可以看到,引用技术帮助宠物中心很好的标记了小狗的使用状态,在完成任务的时候及时收回到宠物中心。


思考几个问题:


  • NSString 引用技术问题


如果我们尝试查看一个string的引用技术

NSString * str = @"hello guys";
NSLog(@"%ld",str.retainCount);


打印结果:

2017-03-27 11:14:33.191171 TextARC[2715:86088] str的引用计数: -1


str的引用计数为-1,这可以理解为NSString实际上是一个字符串常量,是没有引用计数的(或者它的引用计数是一个很大的值(使用%lu可以打印查看),对它做引用计数操作没实质上的影响)。


  • 赋值不会拥有某个对象

NSString * name = dog.name;


这里仅仅是指针赋值操作,并不会增加name的引用计数,需要持有对象必须要发送retain消息


  • dealloc


由于释放对象是会调用dealloc方法,因此重写dealloc方法来查看对象释放的情况,如果没有调用则会造成内存泄露。在上面的例子中我们通过重写dealloc让小狗被释放的时候打印日志来告诉我们已经完成释放。


  • 在上面的例子中,如果我们增加这样一个操作

//没人需要和小狗玩耍了,将其引用计数减1
[dog release];
NSLog(@"小狗的引用计数为·:%ld",dog.retainCount);


会发现获取到的引用计数为1,为什么不是0呢?


这是因为对引用计数为1的对象release时,系统知道该对象将被回收,就不会再对该对象的引用计数进行减1操作,这样可以增加对象回收的效率。


另外,对已释放的对象发送消息是不可取的,因为对象的内存已被回收,如果发送消息时,该内存已经被其他对象使用了,得到的结果是无法确定的,甚至会造成崩溃。


2. 自动释放池


现在已经明确了,当不再使用一个对象时应该将其释放,但是在某些情况下,我们很难理清一个对象什么时候不再使用(比如xiaoming和小狗玩耍结束的时间不确定),这可怎么办


ObjC提供autorelease方法来解决这个问题,当给一个autorelease消息时,方法会在未来某个时间给这个对象发送release消息将其释放,在这个时间段内,对象还是可以使用的。


autorelease的原理是什么呢


原理就是对象接收到autorelease消息时,它会被添加到了当前的自动释放池中,当自动释放池被销毁时,会给池里所有对象发送release消息。


这里就引出了自动释放池这个概念,什么是自动释放池呢?顾名思义,就是一个池,这个池可以容纳对象,而且可以自动释放,这就大大增加了我们处理对象的灵活性。


自动释放池怎么创建?


ObjC提供两种方法创建自动释放池:


方法一:使用NSAutoreleasePool来创建

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


方法二:使用@autoreleasepool创建

@autoreleasepool {
        //这里写代码
    }


自动释放池创建后,就会成为活动的池子,释放池子后,池子将释放其所包含的所有对象。


以上两种方法推荐第一种,因为将内存交给ObjC管理更高效


自动释放池什么时候创建?


app使用过程中,会定期自动生成和销毁自动释放池,一般是在程序事件处理之前创建,当然我们也可以自行创建自动释放池,来达到我们一些特定的目的。


自动释放池什么时候销毁?


自动释放池的销毁时间是确定的,一般是在程序事件处理之后释放,或者由我们自己手动释放

相关文章
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
17天前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
108 66
|
3天前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
|
28天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
1月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
2月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
52 6
|
2月前
|
存储 前端开发 Swift
探索iOS开发:从新手到专家的旅程
本文将带您领略iOS开发的奇妙之旅,从基础概念的理解到高级技巧的掌握,逐步深入iOS的世界。文章不仅分享技术知识,还鼓励读者在编程之路上保持好奇心和创新精神,实现个人成长与技术突破。
|
2月前
|
安全 IDE Swift
探索iOS开发之旅:从初学者到专家
在这篇文章中,我们将一起踏上iOS开发的旅程,从基础概念的理解到深入掌握核心技术。无论你是编程新手还是希望提升技能的开发者,这里都有你需要的指南和启示。我们将通过实际案例和代码示例,展示如何构建一个功能齐全的iOS应用。准备好了吗?让我们一起开始吧!
|
2月前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
34 2
|
2月前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
57 9

热门文章

最新文章