您的位置:时时app平台注册网站 > 编程知识 > iOS内部存款和储蓄器管理【时时app平台注册网站

iOS内部存款和储蓄器管理【时时app平台注册网站

2019-09-16 07:33

在Swift原生数据类型、Foundation框架数据类型和Core Foundation框架数据类型之间转换过程中,虽然是大部分是可以零开销桥接,零开销并不意味着内存什么都不用管。Swift类型内存管理是采用ARC,Foundation类型和Core Foundation类型内存管理都是采用MRC或ARC,Core Foundation类型内存管理是基于C语言风格的,它有一个对象所有权的概念。Objective-C的MRC内存管理Core Foundation的内存管理与Objective-C的MRC内存管理密不可分,先介绍一下Objective-C的MRC内存管理。所有Objective-C类都继承NSObject类,每个NSObject对象都有一个内部计数器,这个计数器跟踪对象的引用次数,被称为“引用计数”(Reference Count,简称RC)。当对象被创建时候,引用计数为1。为了保证对象的存在,可以调用retain方法保持对象,retain方法会使其引用计数加1,如果不需要这个对象可以调用release或autorelease方法,release或autorelease方法使其引用计数减1。当对象的引用计数为0的时候,系统运行环境才会释放对象内存。引用计数示例如图所示,首先在第①步调用者A中创建了一个NSObject对象,这时该对象引用计数为1。在第②步调用者B中想使用这个NSObject对象,于是使用NSObject对象引用,但是为了防止使用过程中NSObject对象被释放,可以调用retain方法使引用计数加1,这时引用计数为2。在第③步调用者A中调用release或autorelease方法,使引用计数减1,这时引用计数为1。在第④步调用者C中调用release或autorelease方法,只是获得NSObject对象引用,并没有调用retain、release或autorelease方法,因此没有引起引用计数的变化。在第⑤步调用者B中调用release或autorelease方法使引用计数减1,这时引用计数为0。这个时候NSObject对象就内存就可以释放了。

——Cocoa Touch设计模式及应用之选择器

实现目标与动作关联使用UIControl类addTarget(_:action:forControlEvents:)方法,示例代码如下:

button.addTarget(self, action: "onClick:",

             forControlEvents: UIControlEvents.TouchUpInside)

其中的action参数"onClick:"事实上就是选择器(Selector)。

通过选择器调用方法,关键是方法名字,它有一定规律的。穷其根本是源自于Objective-C多重参数方法命名规律。方法名的冒号暗示了方法名应该具有几个参数,下面我们看几个示例:

    //选择器为"onClick:"

    func onClick(sender: AnyObject) {

         NSLog("onClick:")

    }

 

    //选择器为"onClick:forEvent:"

    func onClick(sender: AnyObject, forEvent event: UIEvent) {   

          NSLog("onClick:forEvent:")

    }

 

    //选择器为"onClickWithExtSender:forEvent:"

    func onClick(extSender sender: AnyObject, forEvent event: UIEvent) {

          NSLog("onClickWithExtSender:forEvent:")

    }

出于数据封装的需要,我们会在方法前面加private,使其变为私有方法,代码如下。

    private func onClick(sender: AnyObject) {

          NSLog("onClick:")

    }

但是这样方法在调用时候会出现如下错误:
unrecognized selector sent to instance 0x7f7f81499b10'

这个错误的意思是没有找到选择器所指定的方法,也就是没有找到onClick:方法。正确的做法是在方法前面添加@objc属性注释,这说明选择器是在objc runtime运行环境下调用的。

    //选择器为"onClick:"

    @objc private func onClick(sender: AnyObject) {

           NSLog("onClick:")

    }

其实对应的也可以用开关房间的灯为例来说明引用计数的机制。

  1. 谁创建或拷贝对象,他也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者A在第①步,负责创建了NSObject对象,那么调用者A也必须是负责使引用计数减1,见第④步。
  2. 谁调用retain方法使引用计数加1,它也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者B在第②步,调用者B调用NSObject对象retain方法使引用计数加1,那么调用者B也必须是负责使引用计数减1,见第⑤步。对象所有权一个对象可以有一个或多个所有者,从所有者的角度看是对这个对象具有了“所有权”,从上图中看,调用者A和调用者B是所有者,他们可能是一段程序,可能是一个对象。他们对NSObject对象具有所有权,不再使用时候他们应该负责放弃对象所有权,当对象没有所有者时,引用计数为0,它才可以被释放。如上图如果按照对象所有权解释:调用者A创建或拷贝NSObject对象,这时调用者A就具有了NSObject对象的所有权,见第①步。调用者B调用NSObject对象retain方法,就获得了也NSObject对象的所有权,见第②步。调用者A调用NSObject对象release方法,放弃NSObject对象的所有权,见第③步。调用者C只是使用NSObject对象没有获得NSObject对象的所有权,见第④步。调用者B调用NSObject对象release方法,放弃NSObject对象的所有权,见第⑤步,但是调用者B使用这个NSObject对象过程中,由于其他调用者放弃所有权,导致NSObject对象被释放,那么调用者B中程序就会发生运行期错误。

Swift与Objective-C API映射

在混合编程过程中Swift与Objective-C调用是双向的,由于不同语言对于相同API的表述是不同的,他们之间是有某种映射规律的,这种API映射规律主要体现在构造函数和方法两个方面。

1、构造函数映射
在Swift与Objective-C语言进行混合编程时,首先涉及到调用构造函数实例化对象问题,不同语言下构造函数表述形式不同,如图是苹果公司官方API文档,描述了NSString类的一个构造函数。

 

Swift构造函数除了第一个参数外,其它参数的外部名就是选择器对应部分名。规律的其它细节图中已经解释的很清楚了,这个规律反之亦然,这里不再赘述。
2、方法名映射

在Swift与Objective-C语言进行混合编程时,不同语言下方法名表述形式也是不同的,如图是苹果公司官方API文档,描述了NSString类的rangeOfString:options:range:方法。

选择器第一个部分rangeOfString作为方法名,一般情况下Swift方法第一个参数的外部参数名是要省略的,“_”符号表示省略。之后的选择器各部分名(如:options和range),作为外部参数名。除了参数名对应为,参数类型也要对应下来。

Swift 2.0之后方法可以声明抛出错误,这些能抛出错误的方法,不同语言下方法名表述形式如图下图所示,是writeToFile:atomically:encoding:error:苹果公司官方API文档。

比较两种不同语言,我们会发现error参数在Swift语言中不再使用,而是在方法后添加了throws关键字。
这种映射规律不仅仅只适用于苹果公司官方提供的Objective-C类,也适用于自己编写的Objective-C类。

2. Objective-c语言中的ARC下的内存管理(Automatic Reference Counting)

ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。

使用ARC有什么好处呢?

其实大家都知道,自从有了arc之后写Objective-C的代码变得简单多了,因为我们不需要担心烦人的内存管理,担心内存泄露了

代码的总量变少了,看上去清爽了不少,也节省了劳动力

代码高速化,由于使用编译器管理引用计数,减少了低效代码的可能性

但是实质上ARC只能解决iOS开发中的90%的内存管理问题,还有10%的内存管理是需要程序员自己处理的,主要是循环引用和对底层Core Foundatin的调用。

循环引用,其实简单得来讲就是对象A和对象B,互相引用对方作为自己的成员变量,但是由于引用计数的管理方式,只有对象自己销毁的时候,才会将成员变量的引用计数减1,然而对象A和对象B由于都引用了对方,都得不到销毁,这样的情况就是循环引用。当然这只是循环引用的一种情况,多个对象依次持有对方,形成一个环状,也可能造成循环引用,一般来说,环越大就越难被发现。

一般来说,解决循环引用的方法有两个

1)第一个方法是我知道这里会造成循环引用,但是我在使用完了这个功能、方法之后我主动去破除这个循环引用的情况,主动断开循环引用这种操作依赖于程序员自己手工显式地控制,相当于回到了以前 “谁申请谁释放” 的内存管理年代,它依赖于程序员自己有能力发现循环引用并且知道在什么时机断开循环引用回收内存(这通常与具体的业务逻辑相关),所以这种解决方法并不常用,更常见的办法是使用弱引用 (weak reference) 的办法。

2)弱引用虽然持有对象,但是并不增加引用计数,这样就避免了循环引用的产生。在 iOS 开发中,弱引用通常在 delegate 模式中使用。弱引用的实现原理是这样,系统对于每一个有弱引用的对象,都维护一个表来记录它所有的弱引用的指针地址。这样,当一个对象的引用计数为 0 时,系统就通过这张表,找到所有的弱引用指针,继而把它们都置成 nil。一般在block中使用不当也会造成循环引用,例如在使用MJRefresh这个常用的刷新第三方库的时候,要使用__weak 来实现弱引用,避免循环引用

__weak typeof(self) weakself = self;

self.table.mj_header = [MJRefreshGifHeader headerWithRefreshingBlock:^{

       weakself.page = 1;

       weakself.table.mj_footer.hidden = YES;

       [weakself sendRequest];

}];

Core Foundation 对象的内存管理

下面我们就来简单介绍一下对底层 Core Foundation 对象的内存管理。底层的 Core Foundation 对象,在创建时大多以 XxxCreateWithXxx 这样的方式创建,例如:

// 创建一个 CFStringRef 对象

CFStringRef str= CFStringCreateWithCString(kCFAllocatorDefault, “hello world", kCFStringEncodingUTF8);

// 创建一个 CTFontRef 对象

CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);

对于这些对象的引用计数的修改,要相应的使用 CFRetain 和 CFRelease 方法。如下所示:

// 创建一个 CTFontRef 对象

CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);

// 引用计数加 1

CFRetain(fontRef);

// 引用计数减 1

CFRelease(fontRef);

对于 CFRetain 和 CFRelease 两个方法,读者可以直观地认为,这与 Objective-C 对象的 retain 和 release 方法等价。

所以对于底层 Core Foundation 对象,我们只需要延续以前手工管理引用计数的办法即可。

除此之外,还有另外一个问题需要解决。在 ARC 下,我们有时需要将一个 Core Foundation 对象转换成一个 Objective-C 对象,这个时候我们需要告诉编译器,转换过程中的引用计数需要做如何的调整。这就引入了bridge相关的关键字,以下是这些关键字的说明:

__bridge: 只做类型转换,不修改相关对象的引用计数,原来的 Core Foundation 对象在不用时,需要调用 CFRelease 方法。

__bridge_retained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对象在不用时,需要调用 CFRelease 方法。

__bridge_transfer:类型转换后,将该对象的引用计数交给 ARC 管理,Core Foundation 对象在不用时,不再需要调用 CFRelease 方法。

我们根据具体的业务逻辑,合理使用上面的 3 种转换关键字,就可以解决 Core Foundation 对象与 Objective-C 对象相对转换的问题了。

在项目中,其实我们也可以用Instruments来检测我们项目的内存泄漏的问题。

参考文章:

1理解 iOS 的内存管理

2iOS内功篇:内存管理

3iOS内存管理:基本概念与原理

来总结一下:

——Swift与Objective-C混合编程之Swift与Objective-C API映射

Objective-C,顾名思义,是一门超C的语言,自从ARC(Auto Reference Count)出现了之后,我们就很少会去关注关于内存管理这方面的事情了,这些功能的设计者和实现者们为此付出的努力值得我们称赞,但是如果我们对此不知不顾的话,一旦出现了内存泄漏的问题的话,也是个坑,所以先去尝试着去了解它,对我们也不失是一件好事。下面是c语言中的内存分配方式:

时时app平台注册网站 161.gif

——Cocoa Touch设计模式及应用之单例模式

什么是设计模式。设计模式是在特定场景下对特定问题的解决方案,这些解决方案是经过反复论证和测试总结出来的。实际上,除了软件设计,设计模式也被广泛应用于其他领域,比如UI设计和建筑设计等。
下面来介绍Cocoa Touch框架中的设计模式中的单例模式。
单例模式
单例模式的作用是解决“应用中只有一个实例”的一类问题。在Cocoa Touch框架中,有UIApplication、NSUserDefaults和NSNotificationCenter等单例类。另外,NSFileManager和NSBundle类虽然属于Cocoa框架的内容,但也可以在Cocoa Touch框架中使用(Cocoa框架中的单例类有NSFileManager、NSWorkspace和NSApplication等)。
问题提出
在一个应用程序的生命周期中,有时候只需要某个类的一个实例。例如:当iOS应用程序启动时,应用的状态由UIApplication类的一个实例维护,这个实例代表了整个“应用程序对象”,它只能是一个实例,其作用是共享应用程序中的一些资源、控制应用程序的访问,以及保持应用程序的状态等。
解决方案
单例模式的实现有很多方案,苹果公司在《Using Swift with Cocoa and Objective-C》官方文档中给出了一种单例模式的实现。最简单形式代码如下:

class Singleton {

    static let sharedInstance = Singleton()

}

上述代码采用static的类属性实现单例模式,这种类属性只被延迟加载执行一次,即便是在多线程情况下也只是执行一次,并且保证是线程安全的。
如果需要进行一些初始化,可以使用如下带有闭包形式代码:

class Singleton {

    static let sharedInstance: Singleton = {

        let instance = Singleton()

        // 初始化处理

        return instance

    }()

}

iOS开发中,数据类型有两种,一种是int 、float等基本数据类型,而基本数据类型是放在栈上,由系统进行管理,还有一种就是对象,存储在堆上,如果一个对象创建并使用后并没有得到及时的释放,就会一直占用着内存,当这样的对象一直占据着内存得不到释放,这就是我们常说的内存泄漏,严重的话会导致程序崩溃。Objective-C 中的内存管理,其实主要是讲的在堆区上面对内存的管理,而iOS的内存管理机制就是引用计数(reference counting):

原创文章,欢迎转载。转载请注明:关东升的博客

——Core Foundation框架之内存托管对象与非托管对象

Swift中调用Core Foundation函数获得对象时候,对象分为:内存托管对象和内存非托管对象。

·内存托管对象 内存托管对象就是由编译器帮助管理内存,我们不需要调用CFRetain函数获得对象所有权,也不需要调用CFRelease函数放弃对象所有权。
获得这些内存托管对象的方法,是采用了CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED注释声明

func CFStringCreateWithCString(_ alloc: CFAllocator!, 

_ cStr: UnsafePointer<Int8>,

_ encoding: CFStringEncoding) -> CFString!    //内存托管对象

func CFHostCreateCopy(_ alloc: CFAllocator?,

_ host: CFHost) -> Unmanaged<CFHost>        //内存非托管对象

·内存非托管对象
内存非托管对象就是内存需要程序员自己管理。这是由于在获得对象的方法中没有使用CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED注释声明,编译器无法帮助管理内存。在具体使用时候我们可以上一节的方法判断是否为非内存托管对象。
内存非托管对象使用起来有些麻烦,要根据获得所有权方法,进行相应的处理。

  1. 如果一个函数名中包含Create或Copy,则调用者获得这个对象的同时也获得对象所有权,返回值Unmanaged<T>需要调用takeRetainedValue()方法获得对象。调用者不再使用对象时候,Swift代码中需要调用CFRelease函数放弃对象所有权,这是因为Swift是ARC内存管理的。
  2. 如果一个函数名中包含Get,则调用者获得这个对象的同时不会获得对象所有权,返回值Unmanaged<T>需要调用takeUnretainedValue()方法获得对象。

1. Objective-c语言中的MRC(MannulReference Counting)

在MRC的内存管理模式下,与对变量的管理相关的方法有:retain,release和autorelease。retain和release方法操作的是引用记数,当引用记数为零时,便自动释放内存。并且可以用NSAutoreleasePool对象,对加入自动释放池(autorelease调用)的变量进行管理,当drain时回收内存。

1)retain,retain是一个实例方法,只能由对象调用,它的作用是使这个对象的内存空间的引用计数加1,并不会新开辟一块内存空间,通常于赋值是调用,该方法的作用是将内存数据的所有权附给另一指针变量,引用数加1,即retainCount = 1 ; 如:对象2=[对象1 retain];表示对象2同样拥有这块内存的所有权。若只是简单地赋值,如:对象2=对象1;那么当对象1的内存空间被释放的时候,对象2便会成为野指针,再对对象2进行操作便会造成内存错误。

2)release,该方法是释放指针变量对内存数据的所有权,引用数减1,即retainCount-= 1,若引用计数变为0则系统会立刻释放掉这块内存。如果引用计数为0的基础上再调用release,便会造成过度释放,使内存崩溃;

3)autorelease,:autorelease是一个实例方法,同样只能由对象调用,它的作用于release类似,但不是立刻减1,相当于一个延迟的release,通常用于方法返回值的释放,如便利构造器。autorelease会在程序走出自动释放池时执行,通常系统会自动生成自动释放池(即使是MRC下),也可以自己设定自动释放池,如:

@autoreleasepool{

         obj= [[NSObject alloc]init];

         [obj autorelease];

}

当程序走出“}”时obj的引用计数就会减1.

当然自动释放池还有一种写法

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

//这里写代码

[pool release];

但是使用自动释放池需要注意:

1)自动释放池实质上只是在释放的时候給池中所有对象对象发送release消息,不保证对象一定会销毁,如果自动释放池向对象发送release消息后对象的引用计数仍大于1,对象就无法销毁。

2)自动释放池中的对象会集中同一时间释放,如果操作需要生成的对象较多占用内存空间大,可以使用多个释放池来进行优化。比如在一个循环中需要创建大量的临时变量,可以创建内部的池子来降低内存占用峰值。

3)autorelease不会改变对象的引用计数

在mrc中程序员们要遵循下面的基本原则:

1)当你通过new、alloc、copy或mutableCopy方法创建一个对象时,它的引用计数为1,当不再使用该对象时,应该向对象发送release或者autorelease消息释放对象。

2)当你通过其他方法获得一个对象时,如果对象引用计数为1且被设置为autorelease,则不需要执行任何释放对象的操作;

3)如果你打算取得对象所有权,就需要保留对象并在操作完成之后释放,且必须保证retain和release的次数对等。

简单得来说就是谁分配谁释放。

——Cocoa Touch设计模式及应用之响应者链与触摸事件

应用与用户进行交互,依赖于各种各样的事件。事件响应者对象是可以响应事件并对其进行处理的对象,响应者链是由一系列链接在一起的响应者组成的。响应者链在事件处理中是非常重要的,响应者链可以把用
户事件路由给正确的对象。

响应者对象与响应链
UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口。UIApplication、UIView(及其子类,包括UIWindow)和UIViewController(及其子类)都直接或间接地继承自UIResponder类。

 

第一响应者是应用程序中当前负责接收触摸事件的响应者对象(通常是一个UIView对象)。UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。
响应者链是一系列链接在一起的响应者对象,它允许响应者对象将处理事件的责任传递给其他更高级别的对象。随着应用程序寻找能够处理事件的对象,事件就在响应者链中向上传递。响应者链由一系列“下一个响应者”组成。
1.第一响应者将事件传递给它的视图控制器(如果有的话),然后是它的父视图。
2.类似地,视图层次中的每个后续视图都首先传递给它的视图控制器(如果有的话),然后是它的父视图。
3.最上层的容器视图将事件传递给UIWindow对象。
4.UIWindow对象将事件传递给UIApplication单例对象。

触摸事件
触摸(UITouch)对象表示屏幕上的一个触摸事件,访问触摸是通过UIEvent对象传递给事件响应者对象的。触摸对象有时间和空间两方面。
1.时间方面
时间方面信息称为阶段(phase),表示触摸是否刚刚开始、是否正在移动或处于静止状态,以及何时结束,也就是手指何时从屏幕抬起。
在给定的触摸阶段中,如果发生新的触摸动作或已有的触摸动作发生变化,则应用程序就会发送这些消息。

  • 当一个或多个手指触碰屏幕时,发送touchesBegan:withEvent:消息。
  • 当一个或多个手指在屏幕上移动时,发送touchesMoved:withEvent:消息。
  • 当一个或多个手指离开屏幕时,发送touchesEnded:withEvent:消息。

2.空间方面
触摸点对象还包括当前在视图或窗口中的位置信息,以及之前的位置信息(如果有的话)。下面的方法是可以获得触摸点所在窗口或视图中的位置。

    func locationInView(_ view: UIView?) -> CGPoint

获得前一个触摸点所在窗口或视图中的位置信息:

func previousLocationInView(_ view: UIView?) -> CGPoint

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

2)当代码需要使用该对象时,则将对象的引用计数加1

3)当代码结束使用该对象时,则将对象的引用计数减1

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

——Swift与C/C 混合编程之数据类型映射

如果引入必要的头文件,在Objective-C语言中可以使用C数据类型。而在Swift语言中是不能直接使用C数据类型,苹果公司为Swift语言提供与C语言相对应数据类型。这些类型主要包括:C语言基本数据类型和指针类型。

如表所述是Swift数据类型与C语言基本数据类型对应关系表。

Swift语言中的这些数据类型与Swift原生的数据类型一样,本质上都是结构体类型。

如表所述是Swift数据类型与C语言指针数据类型对应关系表。

从表可见针对C语言多样的指针形式,Swift主要通过提供了三种不安全的泛型指针类型:UnsafePointer<T>、UnsafeMutablePointer<T>和AutoreleasingUnsafeMutablePointer<T>。T是泛型占位符,表示不同的数据类型。另外,还有COpaquePointer类型是Swift中无法表示的C指针类型。
下面我们分别介绍一下。

  1. UnsafePointer<T>
    UnsafePointer<T>是一个比较常用的常量指针类型,这种指针对象需要程序员自己手动管理内存,即需要自己申请和释放内存。它一般是由其他的指针创建。它的主要的构造函数有:
    · init( other: COpaquePointer)。通过COpaquePointer类型指针创建。
    · init<U>(
    from: UnsafeMutablePointer<U>)。通过 UnsafeMutablePointer类型指针创建。
    · init<U>(_ from: UnsafePointer<U>)。通过UnsafePointer类型指针创建。
    UnsafePointer<T>主要的属性:
    · memory。只读属性,它能够访问指针指向的内容。
    UnsafePointer<T>主要的方法:
    · successor() -> UnsafePointer<T>。获得指针指向的下一个内存地址的内容。
    · predecessor() -> UnsafePointer<T>。获得指针指向的上一个内存地址的内容。
  2. UnsafeMutablePointer<T>
    UnsafeMutablePointer<T>是一个比较常用的可变指针类型,这种指针对象需要程序员自己手动管理内存,自己负责申请和释放内存。可变指针可以由其他的指针创建,也可以可变指针通过alloc(:)方法申请内存空间,再调用initialize(:)方法初始化指针指向数值。当指针对象释放时候需要调用destroy()方法销毁指针指向对象,它是initialize(:)方法的反向操作,他们两个方法在代码中应该成对出现的。最后还要调用dealloc(:)方法释放指针指向的内存空间,它是alloc(_:)方法的反向操作,这两个方法在代码中也应该成对出现。
  3. AutoreleasingUnsafeMutablePointer<T>
    AutoreleasingUnsafeMutablePointer<T>被称为自动释放指针,在方法或函数中声明为该类型的参数,是输入输出类型的,在调用方法或函数过程中,参数先首先被拷贝到一个无所有权的缓冲区,在方法或函数内使用的这个缓冲区,当方法或函数返回时,缓冲区数据重新写回到参数。
这是我在学Swift整理的基础笔记,希望给更多刚学IOS开发者带来帮助,在这里博主非常感谢大家的支持!  
到这里就基本完成了Swift语言基础笔记整理了。
 如果大家觉得此博文对您有帮助,那就动动你的小手指点个赞!!  
哈哈,感谢各位博友的支持!!!

栈区(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。栈内存分配运算内置于处理器的指令集,效率很高,但是分配的内存容量有限,比如iOS中栈区的大小是2M。(栈系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而堆是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。)

堆区(heap):就是通过new、malloc、realloc分配的内存块,它们的释放编译器不去管,由我们的应用程序去释放。如果应用程序没有释放掉,操作系统会自动回收。分配方式类似于链表。

静态区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。

常量区:常量存储在这里,不允许修改的。

代码区:存放函数体的二进制代码。

——Cocoa Touch设计模式及应用之MVC模式

MVC(Model-View-Controller,模型-视图-控制器)模式是相当古老的设计模式之一,它最早出现在Smalltalk语言中。现在,很多计算机语言和架构都采用了MVC模式。

MVC模式概述
MVC模式是一种复合设计模式,由 “观察者”(Observer)模式、“策略”(Strategy)模式和“合成”(Composite)模式等组成。MVC模式由3个部分组成,如图所示,这3个部分的作用如下所示。
· 模型。保存应用数据的状态,回应视图对状态的查询,处理应用业务逻辑,完成应用的功能,将状态的变化通知视图。
· 视图。为用户展示信息并提供接口。用户通过视图向控制器发出动作请求,然后再向模型发出查询状态的申请,而模型状态的变化会通知给视图。
· 控制器。接收用户请求,根据请求更新模型。另外,控制器还会更新所选择的视图作为对用户请求的回应。控制器是视图和模型的媒介,可以降低视图与模型的耦合度,使视图和模型的权责更加清晰,从而提高开发效率。

 

对应于哲学中的“内容”与“形式”, 在MVC模型中,模式是“内容”,它存储了视图所需要的数据,视图是“形式”,是外部表现方式,而控制器是它们的媒介。
Cocoa Touch中的MVC模式
上面我们讨论的是通用的MVC模式,而Cocoa和Cocoa Touch框架中的MVC模式与传统的MVC模式略有不同,前者的模型与视图不能进行任何通信,所有的通信都是通过控制器完成的,如图所示。

 

在Cocoa Touch框架的UIKit框架中,UIViewController是所有控制器的根类,如UITableViewController、UITabBarController和UINavigationController。UIView是视图和控件的根类。

1)当第一个人进入办公室时,他需要使用灯,于是开灯,引用计数为1

2)每当多一个人进入办公室时,引用计数加1

3)当有一个人离开办公室时,引用计数减1,

4)当引用计数为0时,也就是最后一个人离开办公室时,他不再需要使用灯,关灯离开办公室。(释放对象)

——Core Foundation框架

Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API。虽然在Swift中调用这种C语言风格的API比较麻烦,但是在OS X和iOS开发过程中,有时候使用Core Foundation框架的API是非常方便的,例如在与C语言混合编码的时候。
Core Foundation框架与Foundation框架紧密相关,他们具有与相同的接口,但是不同。Core Foundation框架是基于C语言风格的,而Foundation框架是基于Objective-C语言风格的。在OS X和iOS程序代码中经常会有多种语言风格的代码混合在一起的情况,这使得我们开发变得更加麻烦。
数据类型映射
Core Foundation框架提供了一些不透明的数据类型,这些数据类型封装了一些数据和操作,他们也可以称为“类”,他们都继承于CFType类,CFType是所用Core Foundation框架类型的根类。这些数据类型在Foundation框架中都有相应的数据类型与之对应,这些数据类型也有一些与Swift原生数据类型有对应关系。

看看Swift原生类型与Core Foundation类型之间的转换示例:

import CoreFoundation

import Foundation

var cfstr1: CFString = "Hello,World"    //创建CFString字符串

var str: String = cfstr1 as String     //将CFString字符串转换为Swift原生字符串Stringvar cfstr2: CFString = str            //将Swift原生字符串String转换为CFString字符串

这个转换过程中Core Foundation类型转换为Swift原生类型是需要强制类型转换的。

——Core Foundation框架之内存管理

在Swift原生数据类型、Foundation框架数据类型和Core Foundation框架数据类型之间转换过程中,虽然是大部分是可以零开销桥接,零开销并不意味着内存什么都不用管。Swift类型内存管理是采用ARC,Foundation类型和Core Foundation类型内存管理都是采用MRC或ARC,Core Foundation类型内存管理是基于C语言风格的,它有一个对象所有权的概念。
Objective-C的MRC内存管理
Core Foundation的内存管理与Objective-C的MRC内存管理密不可分,先介绍一下Objective-C的MRC内存管理。
所有Objective-C类都继承NSObject类,每个NSObject对象都有一个内部计数器,这个计数器跟踪对象的引用次数,被称为“引用计数”(Reference Count,简称RC)。当对象被创建时候,引用计数为1。为了保证对象的存在,可以调用retain方法保持对象,retain方法会使其引用计数加1,如果不需要这个对象可以调用release或autorelease方法,release或autorelease方法使其引用计数减1。当对象的引用计数为0的时候,系统运行环境才会释放对象内存。
引用计数示例如图所示,首先在第①步调用者A中创建了一个NSObject对象,这时该对象引用计数为1。在第②步调用者B中想使用这个NSObject对象,于是使用NSObject对象引用,但是为了防止使用过程中NSObject对象被释放,可以调用retain方法使引用计数加1,这时引用计数为2。在第③步调用者A中调用release或autorelease方法,使引用计数减1,这时引用计数为1。在第④步调用者C中调用release或autorelease方法,只是获得NSObject对象引用,并没有调用retain、release或autorelease方法,因此没有引起引用计数的变化。在第⑤步调用者B中调用release或autorelease方法使引用计数减1,这时引用计数为0。这个时候NSObject对象就内存就可以释放了。

来总结一下:

  1. 谁创建或拷贝对象,他也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者A在第①步,负责创建了NSObject对象,那么调用者A也必须是负责使引用计数减1,见第④步。
  2. 谁调用retain方法使引用计数加1,它也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者B在第②步,调用者B调用NSObject对象retain方法使引用计数加1,那么调用者B也必须是负责使引用计数减1,见第⑤步。
    对象所有权
    一个对象可以有一个或多个所有者,从所有者的角度看是对这个对象具有了“所有权”,从上图中看,调用者A和调用者B是所有者,他们可能是一段程序,可能是一个对象。他们对NSObject对象具有所有权,不再使用时候他们应该负责放弃对象所有权,当对象没有所有者时,引用计数为0,它才可以被释放。
    如上图如果按照对象所有权解释:调用者A创建或拷贝NSObject对象,这时调用者A就具有了NSObject对象的所有权,见第①步。调用者B调用NSObject对象retain方法,就获得了也NSObject对象的所有权,见第②步。调用者A调用NSObject对象release方法,放弃NSObject对象的所有权,见第③步。调用者C只是使用NSObject对象没有获得NSObject对象的所有权,见第④步。调用者B调用NSObject对象release方法,放弃NSObject对象的所有权,见第⑤步,但是调用者B使用这个NSObject对象过程中,由于其他调用者放弃所有权,导致NSObject对象被释放,那么调用者B中程序就会发生运行期错误。

这是跟在上一篇博文后续内容:

——Cocoa Touch设计模式及应用之通知机制

通知(Notification)机制是基于观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是 MVC( 模型-视图-控制器)模式的重要组成部分。

在软件系统中,一个对象状态改变也会连带影响其他很多对象的状态发生改变。能够实现这一需求的设计方案有很多,但能够做到复用性强且对象之间匿名通信的,观察者模式是其中最为适合的一个。

通知机制可以实现“一对多”的对象之间的通信。如图所示,在通知机制中对某个通知感兴趣的所有对象都可以成为接收者。首先,这些对象需要向通知中心(NSNotificationCenter)发出addObserver消息进行注册通知,在投送对象通过postNotificationName消息投送通知给通知中心,通知中心就会把通知广播给注册过的接收者。所有的接收者都不知道通知是谁投送的,更不关心它的细节。投送对象与接收者是一对多的关系。接收者如果对通知不再关注,会给通知中心发出removeObserver消息注销通知,以后不再接收通知。

——Cocoa Touch设计模式及应用之目标与动作

目标(Target)与动作(Action)是iOS和OS X应用开发的中事件处理机制。

要实现目标与动作的连接有两种方式:Interface Builder连线实现和编程实现。

  1. Interface Builder连线实现
    Interface Builder连线实现就是故事板或Xib文件中,通过连线而现实。
  2. 编程实现
    编程实现是通过UIControl类addTarget(_:action:forControlEvents:)方法实现的,主要代码如下:

class ViewController: UIViewController {

 

    override func viewDidLoad() {

    super.viewDidLoad()

 

    self.view.backgroundColor = UIColor.whiteColor()

 

    let screen = UIScreen.mainScreen().bounds;

    let labelWidth:CGFloat = 90

    let labelHeight:CGFloat = 20

    let labelTopView:CGFloat = 150

    let label = UILabel(frame: CGRectMake((screen.size.width

             -labelWidth)/2 , labelTopView, labelWidth, labelHeight))

 

    label.text = "Label"

    //字体左右剧中

    label.textAlignment = .Center

    self.view.addSubview(label)

 

    let button = UIButton(type: UIButtonType.System)// 创建UIButton对象

    button.setTitle("OK", forState: UIControlState.Normal)   

 

    let buttonWidth:CGFloat = 60

    let buttonHeight:CGFloat = 20

    let buttonTopView:CGFloat = 240

 

    button.frame = CGRectMake((screen.size.width

         - buttonWidth)/2 , buttonTopView, buttonWidth, buttonHeight)

 

    button.addTarget(self, action: "onClick:",

                     forControlEvents: UIControlEvents.TouchUpInside)

 

    self.view.addSubview(button)   

        }

 

    func onClick(sender: AnyObject) {   

        NSLog("OK Button onClick.")

    }   

        ...

}

上述代码中创建并设置UIButton对象,其中创建UIButton对象,参数type是设置按钮的样式,UIButton样式:

  • Custom。自定义类型。如果不喜欢圆角按钮,可以使用该类型。
  • System。系统默认属性,表示该按钮没有边框,在iOS 7之前按钮默认为圆角矩形。
  • Detail Disclosure。细节展示按钮,主要用于表视图中的细节展示。
  • Info Light和Info Dark。这两个是信息按钮,样式上与细节展示按钮一样,表示有一些信息需要展示,或有可以设置的内容。
  • Add Contact。添加联系人按钮
  • 代码调用addTarget(_:action:forControlEvents:)方法,方法第一个参数是target,即事件处理对象,本例中是self;方法第二个参数是action,即事件处理对象中的方法,
    代码中是"onClick:",方法第三个参数是事件,TouchUpInside事件是按钮的触摸点击事件。
    如果调用如下无参数方法:

func onClick() {
}

调用代码如下:

button.addTarget(self, action: "onClick",

                Ê    forControlEvents: UIControlEvents.TouchUpInside)

区别在于action参数"onClick"方法名不同,action参数方法名的冒号暗示了方法名应该具有几个参数。如果要调用的方法是如下3个参数形式:

func onClick(sender: AnyObject, forEvent event: UIEvent) {

}

那么调用代码如下:

button.addTarget(self, action: "onClick:forEvent:",

                Ê    forControlEvents: UIControlEvents.TouchUpInside)

其中"onClick:forEvent:"是调用方法名,onClick表示方法名也是,forEvent表示第二个参数的外部参数名。

——Swift与Objective-C混合编程之语言

在Swift语言出现之前,开发iOS或OS X应用主要使用Objective-C语言,此外还可以使用C和C 语言,但是UI部分只能使用Objective-C语言。

选择语言
Swift语言出现后,苹果公司给程序员提供了更多的选择,让这两种语言并存。既然是并存,我们就有4种方式可以选择:

  • 采用纯Swift的改革派方式;
  • 采用纯Objective-C的保守派方式;
  • 采用Swift调用Objective-C的左倾改良派方式;
  • 采用Objective-C调用Swift的右倾改良派方式。

文件扩展名

在Xcode等工具开发iOS或OS X应用可以编写多种形式的源文件,原本就可以使用Objective-C、C和C 语言,Swift语言出现后源文件的形式更加多样。可能的文件扩展名说明:

 

本文由时时app平台注册网站发布于编程知识,转载请注明出处:iOS内部存款和储蓄器管理【时时app平台注册网站

关键词: