欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

疯狂iOS上1

程序员文章站 2022-03-31 10:14:28
一:iOS应用与开发环境 1.1 OC与iOS简介 1.2 搭建iOS开发环境 1.3 第一个OC程序 1.4 熟悉Xcode 左边导航面板从左到右依次是:项目导航、符号...

一:iOS应用与开发环境

1.1 OC与iOS简介

1.2 搭建iOS开发环境

1.3 第一个OC程序

1.4 熟悉Xcode

左边导航面板从左到右依次是:项目导航、符号导航、搜索导航、问题导航、测试导航、调试导航、断点导航、日志导航,快捷键是command+1/2

右边检查器面板包括:文件检查器、快速帮助检查器、身份检查器、属性检查器、大小检查器、连接检查器,快捷键是command+option+1/2

右下端库面板包括:文件模板库、代码片段库、对象库、媒体库,快捷键是control+option+command+1;

Xcode的帮助系统:1,利用快速帮助面板 2,直接利用搜索 3,利用编辑区的快速帮助(按住option键)

二:数据类型和运算符

OC是一门强类型的语言,强类型的含义包含两个方面:1,所有变量必须先声明后使用 2,指定类型的变量只能接收类型与之匹配的值

强类型的语言可以在编译过程中发现源代码的错误,从而保证程序更加健壮

2.1 注释

在编写程序时,应该为程序添加一些注释,用以说明某段代码的作用,或者说明某个类的用途,某个方法的功能,以及该方法的参数和返回值的数据类型和意义等,对于一份规范的程序源代码而言,注释应该占到源代码的1/3以上,注释包括两种,单行注释(//abc)和多行注释(/*abc*/)

2.2 标识符和变量

分隔符包括分号(;)、花括号({})、方括号([])、圆括号(())、空格( )、圆点(.)

标识符就是用于给程序中变量、类、方法命名的符号,OC语音的标识符必须以字母、下划线、美元符开头、后面可以跟任意数目的字母、数字、下划线和美元符

2.3 数据类型分类

OC数据类型包括基本类型(包括整型、字符型、浮点型(float/double类型)、枚举型(定义类型:enum season {spring, summer, fall, winter} 定义变量enum season myLove,yourLove))、构造类型(包括数组类型、结构体类型、共用体类型)、指针类型 type varName;

2.4 基本数据类型

2.5 类型转换

OC程序中,不同的基本类型的值经常需要相互转换,一般有两种转换方式,自动类型转换(系统支持)和强制类型转换(运算符是圆括号)

2.6 运算符

运算符是一种特殊的符号,用于表示数据的运算、赋值和比较。OC运算符包括:1,算数运算符 2,赋值运算符 3,比较运算符 4,逻辑运算符 5,位运算符 6,类型相关运算符

运算符的优先级:分隔符(各种括号)>单目运算符>强制类型转换符>乘除求余>加减法>移位运算符>关系运算符>等价运算符>按位与>按位异或>按位或>条件与>条件或>三目运算符>赋值>逗号运算符

1,不要把一个表达式写得过于复杂,如果比较复杂,则应该分成几步来处理

2,不要过多依赖运算符的优先级来控制表达式的执行顺序,这会降低程序的可读性,应尽量使用()来控制表达式的执行顺序

三:流程控制与数组

3.1 顺序结构

顺序结构就是程序从上到下一行一行地执行,中间没有任何判断和跳转

3.2 分支结构

if语句使用布尔表达式或布尔值作为分支条件来进行分支控制if(){}else if(){}else{}

switch语句则用于对多个值进行匹配(byte、short、char、int),从而实现分支控制

switch(){case:condition1{***;break} case:condition2{***;break}default:{***;}}

3.3 循环结构

循环结构包含如下4个部分:1,初始化语句 2,循环条件 3,循环体 4,迭代语句

[init_statements]while(test_expression){statements;[iteration_statements]}

[init_statements]do{statements;[iteration_statements}while{test_expression}

for([init_statements];[test_expression];[iteration_statement]){statements}

3.4 控制循环结构

OC提供了continue和break来控制循环语句,除此之外,return可以结束整个方法,当然也就结束了一次循环

break用于完全结束一个循环,continue的功能和break有点类似,区别是continue只是终止本次循环,接着开始下一次循环,而return是结束整个循环体并结束整个函数,效果范围从小到大依次是continue->break->return

3.5 goto语句

goto语句功能非常强大,它被称为无条件跳转,但由于goto语句功能太强大,而且这种跳转是随心所欲的,因此过度使用会导致程序的可读性大幅度降低,所以建议尽量少用goto语句

3.6 数组

数组定义 type arrayName[length] 元素的地址 = 首地址 + 数组变量所占的内存大小 * 索引

四:C语音特性

4.1 函数

函数返回值 函数名(形参列表){//由零条到多条可执行性语句组成的函数}函数的传值一般都是值传递,将实参的值拷贝一份传入函数

根据函数能否被其他源文件调用,可以将函数分为内部函数和外部函数,内部函数由static修饰,外部函数由extern修饰

4.2 局部变量与全局变量

函数内部定义的变量是局部变量,局部变量在该函数内部有效;函数外部定义的变量是全局变量,全局变量可以被该源文件中的所有函数访问

局部变量根据定义的形式不同又分三种:1,形参 2,函数局部变量 3,代码块局部变量

在函数内部,如果局部变量和全局变量同名,则局部变量会覆盖全局变量,即在函数内部,全局变量会失效

extern修饰的变量称外部全局变量 static修饰的变量称内部全局变量

从变量的存储机制来看,C语音的变量可分为动态存储变量和静态存储变量,动态:程序运行时动态分配内存 静态:运行开始就分配了固定内存

就C语音程序运行的内存来说,大致分为五部分:

程序区(存放函数体的二进制代码)

栈(由编译器自动分配释放 ,存放函数的参数值,局部变量的值等)

堆区(一般由程序员alloc/malloc分配释放, 若程序员不释放,程序结束时可能由OS回收)

全局区(全局/静态变量)

文字常量区(常量字符串就是放在这里的。 程序结束后由系统释放)

静态存储区存放:全局变量和static修饰的局部变量 动态存储区存放:函数的形参变量,非static修饰的局部变量,函数执行现场数据

为了指定变量的存储类型,可以在定义变量时指定存储类别:auto自动存储动态存储区、static静态存储区、register寄存器内 extern外部变量声明

静态局部变量会一直占据固定的内存,所有通常应该慎重使用,一般有两种情况,1,需要变量能保留上一次调用结束时的值 2,希望变量只是被初始化一次,以后只是被引用,而不希望对其重新赋值

4.3 预处理

在编译器对程序进行编译之前,编译器会对这些预处理命令进行处理,然后将这些预处理的结果与源程序一起进行编译,预处理命令通常有两个特征 1,预处理命令都必须以#开头 2,预处理命令通常位于程序开头部分

#define的作用就是为字符串起一个名字,宏名称通常会全大写,宏定义不是变量,也不是常量,没有=,也没有;,其实质是查找替换的过程,如果希望提前结束宏定义,则可以使用如下语句 #undef 宏名称

#ifdef、#ifndef、#else、#endif可执行条件编译 #if、#elif、#else、#endif可执行条件编译

#import比#include更加智能,可判断并且避免重复导入。#import “”先搜索当前路径,再搜索Xcode项目设置的预处理程序的搜索路径,而#import <>直接去搜索特定系统头文件路径中找,而不是在当前路径搜索

4.4 指针

系统需要为内存中的每个单元格编号,32位操作系统最大只能支持4GB的内存,这是因为2的32次方等于4 294 967 296

定义指针变量的语法格式如下:类型 *变量名 整个语法代表定义一个指向特定类型的变量的指针变量,他保存的不是普通的值,而是一个地址

&:取地址运算符 *:取变量运算符

4.5 指针与数组

快速排序

数组变量的本质就是一个指针常量

4.6 字符串与指针

4.7 函数与指针

C语音允许定义一个指针变量来指向函数,然后通过该指针变量来调用函数

1,定义 函数返回值 (* 指针变量名)(); 2,赋值 指针变量名=函数名 3,调用 (*函数指针变量)(参数)

int (*fnPt)() = max; int a = (*fnPt)(data, params);

当函数返回指针时需要注意,如果返回的指针指向的是函数中的局部变量,这将非常危险,因为函数调用结束后,该函数中局部变量所占用的内存已经释放了,那么该指针指向的内存单元格中存储的数据是不确定的

4.8 指针数组和指向指针变量的指针

指针数组的定义 类型 *数组变量[长度],主要不要写成 类型 (*数组变量)[长度] 此表示指向一个一维数组的指针

指向指针的指针 类型 **变量名

4.9 结构体

定义结构体 struct 结构体类型名{//成员列表} 定义结构体变量 struct 结构体类型名 变量名;

struct 结构体类型名{//成员列表}结构体变量1,结构体变量2;

每次定义结构体变量都会很繁琐,可以使用#define POINT struct 结构体类型名 来预编译,也可以使用typedef来为已有的结构体类型定义新的名词 typedef struct 结构体类名 POINT

C语言要求在定义结构体变量时执行初始化,一旦初始化完成,或定义结构体变量时没有执行初始化,那么程序以后就不能对结构体变量整体赋值了,但可以将一个结构体变量赋值给另一个结构体变量

4.10 块(Block)

块(Block)是OC对C语音做的扩展,使用块可以更好地简化OC编程,而且OC的很多API都依赖于块

块的定义语法:^[块返回值类型](形参类型1 形参1,形参类型2 形参2,…){//块执行体}

块定义与函数定义的区别:1,^开头 2,返回值类型可省略 3,无需指定块名 4,参数部分的括号不可省略,如果没参数,用void代替

可以定义块变量:块返回值类型 (^块变量名)(形参类型1,形参类型2,…);

_block修饰的局部变量表示,无论何时,块都会直接使用该局部变量本身,而不是将局部变量的值赋值到块范围内

可以直接使用块作为函数的参数

使用typedef可以定义块类型,用途主要有二 1,复用块类型,可以定义出多个块变量 2,使用块类型定义函数参数

定义块类型的语法格式:typedef 块返回值类型 (^块类型)(形参类型1 形参1, 形参类型2 形参2,…);

五:面向对象(上)

5.1 类和对象

我们可以把类当成一种自定义数据类型,可以使用类来定义变量,这种类型的变量相当于指针类型的变量。OC中定义类分为两个步骤:1,接口部分:定义该类包含的成员变量和方法 2,实现部分:为该类的方法提供实现,OC将类分为接口部分和实现部分体现了良好的封装意识,在接口部分定义的内容(包括成员变量和方法)都是可以暴露且可供用户调用的部分,实现部分则属于类的内部实现,对于外界而言是隐藏的,不能供外界调用

OC语言关于方法调用有两种说法,调用方法和发送消息,对于[person abc]语句,可以说成person对象调用abc方法,此时person是方法调用者,也可以说成向person发送abc消息,此时person是消息接收者

类是一种指针类型的变量,因此,程序中定义的FKPerson类型只是存放一个地址值,被保存在动态存储区,它指向实际的FKPerson对象,而真正的FKPerson存放在堆内存中

OC提供了一个id类型,这个类型可以代表所有的对象的类型,程序在编译时不需要确定类型,而在运行时才确定变量类型和调用的方法

5.2 方法详解

如果在定义方法时,在最后一个形参名后增加逗号和三点,则表明该形参可以接受多个参数值

va_list 这是一个类型,用于定义指向可变参数列表的指针变量 va_list argList;

va_start 这是一个函数,该函数指定开始处理可变形参的列表,并让指针变量指向可变形参的第一个参数 va_start(argList, name)

va_arg 这是一个函数,该函数返回指针当前指向的参数的值,并将指针移动到指向下一个参数NSString*arg=va_arg(argList, id)

va_end 结束处理可变形参,释放指针变量

va_list argList;

va_start(argList, name);//name为传入的第一个参数名

NSString *arg=va_arg(argList, id);

while(arg){NSLog(@“arg=%@”,arg);arg=va_arg(argList, id);}

va_end(argList);

5.3 成员变量

OC中根据定义变量位置不同,可以将变量分成三大类,成员变量,局部变量和全局变量,成员变量是指在类的接口部分或实现部分定义的变量

虽然OC也提供了static关键字,但这个static关键字不能用于修饰成员变量,它只能修饰局部变量、全局变量和函数,static修改局部变量表示将该局部变量存储到静态存储区,static修改全局变量用于限制改全局变量只能在当前文件源中访问,static修饰函数用于限制该函数只能在当前源文件中调用

为了模拟类变量,可以在类实现部分定义一个static修改的全局变量,并提供一个类方法来暴露该全局变量

在某些时候,程序多次创建某个类的对象没有任何意义,还可能造成系统性能下降,此时程序需要保证该类只有一个实例

static id instance; + (id)instance{if(!instance) {instance=[[super alloc] init];}return instance;}

5.4 隐藏和封装

封装(Encapsulation)是面向对象的三大特征之一(另外两种是继承和多态),它指的是对象的状态信息隐藏在对象内部,1,不允许外部程序直接访问对象内部信息,2,而是通过该类所提供的方法来实现对内部信息的操作和访问

OC提供了4个访问控制符:@private当前类访问权限 @package相同映像访问权限 @protected子类访问权限 @public公共访问权限

所谓相同映像,简单的说,就是编译后生成的同一个框架或同一个执行文件(.out文件)

每个类常常就是一个小的模块,模块的设计需要遵循高内聚,低耦合的原则。

5.5 键值编码(KVC)与键值监听(KVO)

KVC(key Value Coding)键值编码,允许以字符串形式间接操作对象的属性。-setValue:forKey:/-valueForKey:程序先考虑调用SetName:方法,再找_name的成员变量,然后再找name的成员变量,最后调用setValue:forUndefinedKey:方法返回异常

-(void)setValue:(id) value forUndefinedKey:(id)key {NSLog(@“您尝试设置的key值不存在”)}

-(id)valueForUndefinedKey:(id)key{NSLog(@“您尝试访问的key并不存在”)}

如果为基本类型设置属性为nil,会出现异常,同样需要通过-(void)setNilValueForKey:(id)key{if([key isEqualToString:@“price”]){_price=0;}else{[super setNilValueForKey:key}}

KVO(Key Value Observing)键值监听,iOS应用将程序组件分开成数据模型组件和视图组件,当数据模型组件发送变化时,可通过KVO监听其变化从而修改视图组件的属性

-(Object*)addObserver:forKeyPath:options:context:/-removeObserver:forKeyPath:/context:添加、删除监听

-(void)observeValueForKeyPath:ofObject:change:context:

5.6 对象初始化

alloc分配内存,init完成初始化,还可以提供更多的便利初始化,如-(id)initWithBrand:(NSString *)brand;

5.7 类的继承

OC只能单继承,每个子类最多只有一个直接父类,方法的重写必须注意方法签名关键字要完全相同,也就是方法名和方法签名中的形参标签都需要完全相同,否则就不能算方法重写或方法覆盖

无论父类接口部分的成员变量使用何种访问控制符限制,子类接口部分定义的成员变量都不允许与父类接口部分定义的成员变量重名

在类实现部分定义的成员变量将被限制在该类内部,因此,父类在类实现部分定义的成员变量对子类没有任何影响,子类此时会隐藏父类的变量

5.8 多态

OC指针类型的变量有两个,一个是编译时类型,一个是运行时类型。编译时的类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态(Polymorphism),即相同类型的变量调用同一个方法呈现出多种不同的行为特征。指针变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行其运行时类型所具有的方法

指针变量的强制类型转换:(type*)variable;

当把子类对象赋值给父类指针变量时,被称为向上转型(upcasting),这种转型总是可以成功的,执行方法时,依然表现出子类对象的行为模式,但把一个父对象赋值给子类指针变量时,就需要进行强制类型转换,而且还可能运行时产生错误,所以在强制转换之前需要先判断

-isMemberOfClass:(是否为实例) -isKindOfClass:(是否为类或子类) -isSubClassOfClass:(子类)

六:面向对象(下)

6.1 OC的包装类

在开发iOS时,可能会遇到NSInteger、NSUInteger、CGFloat类型,它的存在是为了更好的兼容不同的平台

如#if _LP64_ typedef long NSInteger #else typedef int NSInteger #endif

[NSNumber numberWithXXX][number initWithXXX][number XXXValue]

6.2 处理对象

NSLog(@“%@”, p)输出的是p类的description方法返回值 -(NSString *)description{return @“”};

==如果是判断基本类型,只要两个变量的值相等即可,如果是两个指针类型的变量,他们必须指向同一个对象

isEqual默认也是比较地址,但一般需要重写才用,重写后要满足下列条件1,自反性[x isEqual:x]返回真 2,对称性[y isEqual:x]则[x isEqual:y] 3,传递性若[x isEqual:y][y isEqual:z]则[x isEqual:z] 4,一致性,判断多次结果一定 5,[x isEqual:nil]假

6.3 扩展与类别

由于OC并没有提供抽象类的语法支持,而在实际项目开发中,总需要有抽象类的时候,此时就会定义一个父类,并以该父类派生多个子类,其他程序使用这些类时,总是面向父类编程,当程序调用父类的初始化方法、类方法来返回对象时,实际上返回的是子类的实例,这一系列的类被称为一个类簇(cluster),这个父类也就模拟了抽象类的功能。

OC的动态特征允许使用类别为现有的类添加新方法,并且不需要创建子类,不需要访问原有类的源代码

@interface 已有类 (类别名) @end @impletation 已有类 (类别名) @end

类别可以重写原有类中的方法,但通常并不推荐这么做,如果需要重写原有类方法,一般通过原有类派生子类,在子类中重写父类原有的方法

通过类别为指定类添加新方法后,这个新方法还会添加到这个类的子类当中去,一个类可以增加多个类别,这些类别都可增加原有类的方法

类别的用法:1,对类进行模块化设计 2,使用类别调用私有方法 3,使用类别实现非正式协议

扩展与类别相似,扩展相当于匿名类别@interface 已有类() @end,但就用法来看,类别通常有单独的.h和.m文件,扩展则用于临时对某个类的接口进行扩展,类实现部分同时实现类接口部分定义的方法和扩展中定义的方法,在定义类的扩展时,可以额外增加实例变量,也可以使用@property来合成属性,但定义类的类别时,则不允许额外定义实例变量,也不能用@property合成属性

6.4 协议(protocol)与委托(delegate)

协议定义的是多个类共同的公共行为规范,这些行为是与外部交流的通道,这就意味着协议里通常是定义一组公共方法,但不会为这些方法提供实现,方法的实现交给类去完成,即委托该类去调用方法完成任务。

利用类别可以实现非正式协议,这种类别以NSObject为基础,为NSObject创建类别,创建类别即可指定该类别应该新增的方法。当某个类实现NSObject的该类别时,就需要实现该类别下的所有方法,这种基于NSObject定义的类别即可认为是非正式协议。需要指出的是,对于实现非正式协议的类而言,OC编译器并不强制实现该协议中的所有方法,但如果不实现,运行时该程序就会引起错误

正式协议不再使用@interface、@implementation关键字,而是使用@protocol关键字@protocol协议名<父协议1,父协议2>{}

协议名应与类名有相同的命名规则,一个协议可以有多个直接父协议,协议定义的方法只有方法签名,没有方法实现,可包含类方法和实例方法

如果需要使用协议来定义变量,则有如下两种语法:1,NSObject<协议1,协议2> *变量=*** 2,id<协议1,协议2>变量=***

对比正式协议和非正式协议,不难发现存在如下差异

1,非正式协议通过NSObject创建类别来实现,而正式协议则直接使用@protocol创建

2,遵守非正式协议通过继承带特定类别的NSObject来实现,而遵守正式协议则有专门的OC语法

3,遵守非正式协议不要求实现协议中定义的所有方法,而遵守正式协议则必须实现协议中定义的所有方法

为了弥补正式协议必须实现协议的所有方法造成的灵活性不足,OC2.0新增了optional和required两个关键字

6.5 使用@try处理异常

OC的异常机制并不作为常规的编程实践,通常只是作为一种程序调试排错机制

@try{代码操作}@catch(异常1 ex){ex.name,ex.reason,ex.userInfo处理异常}@catch(异常2 ex){}@finally{回收资源}

如果在某些时候,某些数据与业务规则不匹配,系统无法抛出这种异常,则需要在程序中使用@throw语句自行抛出异常,也可以抛出继承于NSException的自定义异常来@catch

6.6 OC反射机制

OC提供了3种编程方式与运行环境交互 1,直接通过OC的源代码 2,通过NSObject类中定义的方法进行动态编程 3,直接调用运行时函数进行动态编程

在OC中获得Class的方式有3种,1,使用Class NSClassFromString(NSString *className) 2,调用某个类的class方法来获取该类对应的Class 3,调用某个对象的class方法来获取该类对应的class

检查继承关系:-isKindOfClass/-isMemberOfClass/conformsProtocol:@protocol(ProtocolName)/NSProtocolFromString(ProtocolName)

如果需要调用类中的变量,则可根据KVC机制来设置,访问

如果程序需要判断某个对象是否可调用某个方法,可通过respondsToSelector:@selector(selectorName)/NSSelectorFromString(selectorName)来判断

如果程序需要动态调用对象的普通方法,则可通过两种方式来实现

1,[self performSelector:@selector(selectorName)/NSSelectorFromString(selectorName) withObject:]

2,objc_msgSend(self, @selector(selectorName)/NSSelectorFromString(selectorName), …)

3,IMP方法的函数指针 -(IMP)methodForSelector:@selector(selectorName)/NSSelectorFromString(selectorName)

double (*addSpeed)(id, SEL, double);返回值类型 (*指针变量名)(方法调用者, 方法, 方法参数)

addSpeed=(double(*)(id, SEL, double))[car methodForSelector:NSSelectorForString(@“addSpeed:”)]

double speed = addSpeed(car, @selector(addSpeed:), 2.4);

在开发了大量iOS项目之后,就会发现有大量代码是类似的,如果把这些通用的代码抽取成为更通用的框架,那么程序将会拥有更好的架构,当需要开发出那些具有通用性质的框架时,这些框架代码无法预先知道被调用组件的实现类,以及具有哪些方法,这些信息可能是通过配置文件给的,而这些框架必须动态地根据字符串来创建对象,根据字符来决定要初始化哪个类,调用哪个方法,这些功能都必须借助OC的反射、动态机制来实现。

6.7 手动内存管理

如果一直在分配内存,而没有回收他们,就会出现内存泄露。OC的内存回收机制有3种,1,手动引用计数和自动释放池 2,自动引用计数(ARC) 3,自动垃圾回收(Mac应用独有)

OC采用一种被称为引用计数(Reference Counting)的机制来跟踪对象的状态,每个对象都有一个与之关联的整数,被称为引用计数

当程序调用方法名以alloc、new、copy、mutableCopy开头的方法来创建对象时,该对象的引用计数加1

调用对象的retain方法时,该对象的引用计数加1,调用对象的release方法时,引用计数减1,当引用计数为0时,系统自动dealloc销毁

-autorelease:不改变该对象的引用计数的值,只是将该对象添加到自动释放池中 -retainCount返回该对象的引用计数的值

所谓自动释放池,就是一个存放对象的容器,自动释放池会保证延迟释放该池中所有的对象。-(id)autorelease:添加到自动释放池中

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

对于Foundation框架中的类而言,当调用方法创建对象时,只要这些方法不是以alloc,new,copy,mutableCopy(本来不会自动释放)开头的,系统就会默认创建自动释放对象,当自动释放池释放时,该对象就被自动释放,可称之为临时对象,在iOS的事件循环时,步骤1,创建自动释放池 2创建事件处理方法 3销毁自动释放池 4处理完成,所以在iOS事件循环中,应避免临时对象的出现,或通过如下方式避免事件结束时对象被回收1,在将临时对象赋值之前,先调用临时对象的retain方法将它的引用计数加1 2,把临时对象赋值给retain、strong或copy指示符修饰的属性

手动内存管理的规则总结:

1,调用对象的release方法并不是销毁该对象,而是将该对象的引用计数减1,当一个对象的引用计数为0时,系统自动调用dealloc来销毁

2,当自动释放池被回收时,自动释放池会依次调用每个对象的release方法,如果release后引用计数为0则销毁,否则该对象可以活下来

3,程序使用以alloc,new,copy,mutableCopy开头的方法创建对象,该对象引用计数为1,当不再使用,需release或autorelease

4,如果使用retain方法为对象增加过引用计数,则需要调用release来减少该对象的引用计数,并保证retain次数和release次数相等

5,如果在自动释放池中创建了一个临时对象,则系统会自动回收该对象,如果程序需要保留此对象,则需手动调用retain来增加引用计数

七:Foundation框架详解

7.1 字符串(NSString与NSMutableString)

- (NSString *)substringFromIndex:(NSUInteger)from;

- (void)getCharacters:(unichar *)buffer range:(NSRange)range;

- (BOOL)hasSuffix:(NSString *)str;

- (NSRange)rangeOfString:(NSString *)searchString;

- (NSString *)stringByAppendingString:(NSString *)aString;

- (NSString *)uppercaseStringWithLocale:(nullable NSLocale *)locale;

- (NSArray *)componentsSeparatedByString:(NSString *)separator;

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString;

- (nullable id)initWithContentsOfFile:(NSString *)path;

7.2 日期与时间

[NSDate date]/[[NSDate alloc] initWithTimeIntervalSinceNow:]/[NSDate dateWithTimeIntervalSince1970]

[date timeIntervalSinceDate:][date timeIntervalSinceNow:]

[NSDateFormatter setDateFormat:][NSDateFormatter stringFromDate:][NSDateFormatter dateFromString:]

NSDateComponents(日期组件)和NSDate之间可以通过NSCalendar进行相互转换,它包括如下两个方法:

-(NSDateComponents*)components:(指定年月日)fromDate:/-(NSDate*)dateFromComponents:

[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:]

[NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:]

NSInvocation对象也是封装target和selector的

7.3 对象复制

NSObject类提供了copy和mutableCopy方法来复制已有对象的副本,copy方法返回该对象的不可修改的副本,mutableCopy返回该对象可修改的副本,如果是自定义类,则必须实现NSCopying或NSMutableCopying协议的copyWithZone:或mutableCopyWithZone:方法

如果程序只复制指针的地址而不是复制指针所指的对象,称之为浅度复制,深度复制不仅会复制对象本身,且会递归复制每个指针类型的属性,直到两个对象没有任何共用的部分,一般来说,深度复制的实现难度大很多,Foundation框架中的类大部分都只实现了浅复制。

setter方法的复制选项可以使用copy指示符,即-(void)setName:(NSMutableString*)name {name=[name copy]}

7.4 OC集合概述

OC集合大致分为NSArray,NSSet和NSDictionary

7.5 数组(NSArray与NSMutableArray)

数组代表元素有序、可重复的一个集合,集合中每个元素都有其对应的顺序索引

-array: -arrayWithContentsOfFile: -initWithContentsOfFile: -arrayWithObject/s: -initWithObject/s:

NSArray如何判定集合是否包含指定元素?只有某个集合元素与被查找元素通过isEqual方法比较返回YES时,认为包含该元素

NSArray可以对集合中所有的元素或部分元素整体调用方法

[array makeObjectsPerformSelector:]/[array makeObjectsPerformSelector:withObject:]

[array enumerateObjects/WithOptions:UsingBlock:][array enumerateObjectsAtIndexes:options:usingBlock:]

[array sortedArrayUsingFunction:context:/UsingSelector:/UsingComparator:]

使用枚举器遍历[array objectEnumerator][array reverseObjectEnumerator][en allObjects][en nextObject]

NSArray允许KVC编码 -setValue:forKey:(全部修改)/-(NSArray*)valueForKey:

NSArray支持KVO监听 -addObserver:forKeyPath:options:context:/-removeObserver:forKeyPath:

-addObserver:toObjectsAtIndexPath:forKeyPath:options:context:/-removeObserver:fromObjectsAtIndexes:forKeyPath:

7.6 集合(NSSet与NSMutableSet)

NSSet集合里多个对象之间没有明显的顺序,且每个元素不会相同

-setByAddingObject: -setByAddingObjectsFromSet: -setByAddingObjectsFromArray: -allObject: -anyObject: -containsObject: -member:(判断该集合是否包含与该参数相等的元素) -objectsPassingTest:(参数为一个代码块,选出满足该代码块条件的集合元素) -objectsWithOptions:passingTest:(与前者功能相似,只是额外传入一个NSEnumerationOptions迭代参数选项,NSArray也提供了这两个方法,只不过这些方法返回的是符合条件的集合元素的索引组成的NSIndexSet集合) -isSubsetOfSet: -intersectsSet: -isEqualToSet:

NSSet判断两个元素相等的标准 1,两个对象通过isEqual方法比较返回YES 2,两个对象的hash方法返回值相等

hash方法的基本规则,1,同一个对象多次调用hash方法返回相同的值 2,如果isEqual方法返回YES,则hash返回值也应该相等 3,对象中作为isEqual方法比较标准的成员变量,都应该用来计算hashcode值

-addObject: -removeObject: -removeAllObjects: -addObjectsFromArray: -unionSet: -minusSet: -intersectSet:

NSCountedSet是NSMutableSet的子类,它为每个元素额外维护一个添加次数的标记

-countForObject:

7.7 有序集合(NSOrderedSet与NSMutableOrderedSet)

NSOrderedSet既不允许元素重复,又可以保持顺序添加

7.8 字典(NSDictionary与NSMutableDictionary)

NSDictionary用于保持具有映射关系的数据,因此,NSDictionary集合里保存着两组值,一组用于保存NSDictionary里的key,另一组用户保存NSDictionary里的value,key和value都可以是任何引用类型的数组,Map的key不允许重复

-dictionary: -dictionaryWithContentsOfFile:/-initWithContentsOfFile: -dictionaryWithDictionary: -dictionaryWithObject:forKey: -dictionaryWithObjects:forKeys: -dictionaryWithObjectsAndKeys:

-count: -allKeys: -allKeysForObject:(指定该对象对应的全部key) -allValues: -objectForKey: -objectForKeyedSubscript:(允许NSDictionary通过下标方法来获取指定key对应的value) -valueForKey: -keyEnumerator: -objectEnumerator: -enumerateKeysAndObjectsUsingBlock:迭代执行集合中的所有键值对 -enumerateKeysAndObjectsWithOptions:usingBlock: -writeToFile:atomically

-(NSArray)keysSortedByValueUsingSelector: -keysSortedByValue/WithOptions:UsingComparator:

-(NSSet)keysOfEntriesPassingTest:(key, value, isEnumerator)使用代码块处理,对key过滤,第一个是key,第二个是value,第三个是是否还需要继续迭代,如果为NO,则会立即停止迭代

-(NSSet)keysOfEntriesWithOptions:passingTest:

如果使用自定义类作为NSDictionary的key值,则自定义类必须满足两个要求,1,正确重写过isEqual:和hash方法,2,实现了copyWithZone方法,即继承了NSCopying协议,因为为了保持NSDictionary的键值不被破坏,NSDictionary总会先调用该key的copy方法来复制该对象的不可变副本

NSMutableDictionary: -setObject:forKey: -setObject:forKeyedSubscript: -addEntriesFromDictionary: -setDictionary: -removeObjectForKey: -removeAllObjects: -removeObjectsForKeys:

7.9 谓词

NSPredicate用于定义一个逻辑条件,通过该条件可以执行搜索或内存中的过滤操作

三个子类:NSComparisonPredicate/NSCompoundPredicate/NSExpresion

[NSPredicate predicateWithFormat:][predicate predicateWithSubstitutionVariables:]//为占位符参数设置参数值[predicate evaluateWithObject:]

使用谓词过滤不可变集合时,方法将会返回符合条件的集合元素组成的新集合,过滤可变集合时,方法直接删除不符合谓词条件的元素

NSArray: -(NSArray)filteredArrayUsingPredicate:(返回符合条件的元素组成的心数组)

NSMutableArray: -filterUsingPredicate:使用指定的谓词过滤NSArray集合,删除不符合条件的元素

NSSet: -(NSSet)filteredSetUsingPredicate:

NSMutableSet: -filterUsingPredicate:

如果需要在谓词表达式中使用变量,则可以在谓词表达式中使用占位符参数,参数支持三个占位符参数 1.%K动态传入属性名 2.%@动态设置属性值 3.$SUBSTR设置变量

[NSPredicate predicateWithFormat:@“%K contains %@”, @“name”, @“value”]

[NSPredicate predicateWithFormat:@“%K contains $SUBSTR”, @“name”]

[predicate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:@“1”,@“SUBSTR”]

[predicate evaluateWithObject:substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:]

谓词表达式由表达式、运算符和值组成

比较运算符:=/==/>=/=>/<=/=//BETWEEN

逻辑运算符:AND/&&/OR/||/NOT/!

字符串比较运算符:BeginWith/EndWith/CONTAINS/LIKE(*代表任意多个字符,?代表一个字符)/MATCHES

操作集合运算符ANY/SOME/ALL/NONE/IN

直接量FALSE/NO/TRUE/YES/NULL/NIL/SELF

保留字 FIRST/LAST/SIZE/ANYKEY/CAST/TruePredicate/FalsePredicate

八:文件I/O

8.1 使用NSData与NSMutableData

NSData与NSMutableData代表OC的数据缓冲区,可以通过类的方法来创建,也可以通过实例的方法来创建

[NSData data]/[NSData dataWithBytes:length:]/[[NSData alloc] initWithBytes:length:]

[NSData dataWithBytesNoCopy:length:][[NSData alloc] initWithBytesNoCopy:length]NSData销毁自己时程序会释放该数组

[NSData dataWithBytesNoCopy:length:freeWhenDone]freeWhenDone为YES,销毁自己时程序会释放该数组

[NSData dataWithContentsOfFile:][[NSData alloc] initWithContentsOfFile]根据文件内容来初始化NSData

[NSData dataWithContentsOfURL:][[NSData alloc] initWithContentsOfURL]根据URL关联的内容初始化NSData

[NSData dataWithData:][[NSData alloc] initWithData:]使用NSData初始化另一个NSData

-bytes返回NSData所包含的数据 -getBytes:length获取NSData所包含的指定长度的数据并将其写入byte数组 -getBytes:range获取NSData所包含的指定范围的数据并将其写入byte数组 -subdataWithRange获取指定范围的NSData对象 -writeToFile:atomically将NSData的数据写入文件 -writeToURL:atomically将NSData的数据写入URL对应的资源

8.2 使用NSFileManager管理文件和目录

绝对路径:以斜线开头的路径 相对路径:不以斜线开头的路径 ~代表当前用户的home路径 .代表当前目录 ..代表上一级目录

-fileExistsAtPath:文件是否存在 -fileExistsAtPath:isDirectory:后一个参数返回是否为目录

-isReadable/Writable/Executable/DeletableFileAtPath:判断文件是否可读,可写,可执行,可删除

-componentsToDisplayForPath:获取文件的各个路径组件 -displayNameAtPath:获取文件的简单文件名

-attributesOfItemAtPath:error:获取文件属性 -attributesOfFileSystemForPath:error:获取文件系统的属性

-contentsAtPath:获取指定的路径的NSData内容 -contentsEqualAtPath:andPath:判断两个文件内容是否相同

-createDirectoryAtURL:withIntermediateDirectories:attributes:error:根据指定的URL创建目录

-createDirectoryAtPath:withIntermediateDirectories:attributes:error:根据路径创建目录,父目录不存在则创建

-createFileAtPath:content:attributes:根据指定的路径、内容、属性创建文件

-removeItemAtURL:error: -removeItemAtPath:error: -copyItemAtURL:toURL:error: -copyItemAtPath:toPath:error: -moveItemAtURL:toURL:error: -moveItemAtPath:toPath:error:

-(NSArray)contentsOfDirectoryAtPath:error:获取指定目录下的所有文件和子目录,对于子目录,不会递归枚举

-(NSDirectoryEnumerator)enumeratorAtPath:获取指定目录下的文件和子目录枚举器,调用skipDescendants阻止递归子目录

-(NSArray)subpathsOfDirectoryAtPath:error:递归获取指定路径包含的所有目录及子目录-subpathsAtPath:

8.3 使用NSPathUtilities.h管理路径

NSPathUtilities.h对NSString类扩展了如下方法:

+pathWithComponents:components:根据components中的元素构造有效的路径

-pathComponents: -isAbsolutePath: -lastPathComponent: -pathExtension:

-stringByAbbreviatingWithTildeInPath:将路径中当前用户的home路径替换为~将路径中用户的home路径替换为~user形式,Abbreviating简写,Tilde波浪符

-stringByAppendingPathComponent:path: -stringByAppendingPathExtension:ext: -stringByDeletingLastPathComponent: -stringByDeletingPathExtension:

-stringByExpandingTildeInPath:将~和~user替换为绝对路径

-stringByResolvingSymlinksInPath:解析路径中的符号链接,返回解析后的路径

-stringByStandardisingPath 解析路径中的~/./..,返回解析后的路经,standardising解析

NSUserName(),NSFullUserName(),NSHomeDirectory(),NSHomeDirectoryForUser(user),NSTemporaryDirectory()

8.4 使用NSProcessInfo获取进程信息

NSProcessInfo *info = [NSProcessInfo processInfo];

info.arguments程序运行时传入的参数 environment环境变量 processIdentifier进程标识符 globallyUniqueString进程的全局唯一子串 processName进程名 hostName主机名 operatingSystemVersion操作系统版本 operatingSystemVersionString操作系统版本号 isOperatingSystemAtLeastVersion操作系统版本是否不低于给定版本 physicalMemory系统物理内存 processorCountCPU数量 activeProcessorCount激活状态的CPU数量 systemUptime系统已运行的时间

8.5 使用NSFileHandle处理文件IO

NSFileHandle没有创建文件的功能,它提供了处理文件IO的相关方法

+fileHandleForReadingAtPath: +fileHandleForReadingFromURL:error:

+fileHandleForWritingAtPath: +fileHandleForWritingToURL:error:

+fileHandleForUpdatingAtPath: +fileHandleForUpdatingURL:error:

+fileHandleWithStandardError/Input/Output/NullDevice:(标准输入,即键盘,标准输出,即屏幕)

-fileDescriptor: -availableData: -readDataToEndOfFile: -readDataOfLength:length: -writeData: -offsetInFile: -seekToEndOfFile: -seekToFileOffset:offset: -closeFile: -truncateFileAtOffset:offset

8.6 使用NSURL读取网络资源

URL(Uniform Resource Locator)对象代表统一资源定位器,它是指向互联网资源的指针.通常为scheme://host:port/path

8.7 使用NSBundle处理项目相关资源

如果应用使用绝对或相对路径地址去访问文件,则会导致程序的可移植性降低,可以把项目资源文件放在应用中,让应用自己包含这些资源文件,接下来就可以使用NSBundle来访问这种应用包含的资源文件了。NSBundle *bundle = [NSBundle mainBundle];

-URLForResource:withExtension:subdirectory: -URLForResource:withExtension:

-pathForResource:ofType: -URLsForResourcesWithExtension:subdirectory:

-pathForResource:ofType:inDirectory: -pathsForResource:ofType:inDirectory:

-resourcePath:返回该NSBundle的子目录所包含资源的完整路径

8.8 对象归档

所谓对象归档,就是类似于其他语言的序列化机制,归档就是用某种格式把一个或多个对象保存到指定文件中,方便以后从文件中恢复他们。

+(NSData*)archivedDataWithRootObject:/+(BOOL)archiveRootObject:toFile:

+(id)unarchiveObjectWithData:/+(id)unarchiveObjectWithFile:

如果需要将自定义的类进行归档和解档操作,则自定义类必须实现NSCoding协议,两个方法-encodeWithCoder:/-initWithCoder:

可以结合NSData完成很多对象的自定义归档

NSKeyArchiver *arch = [NSKeyArchiver alloc] initForWritingWithMutableData:[NSMutableData data]];

[arch encodeObject:forKey:];[arch finishEncoding];[data writeToFile:];

NSKeyUnarchiver *un=[[NSKeyUnarchiver alloc] initForReadingWithData:[NSData dataWithContentsOfFile:]]

[un decodeObjectForKey:];[un finishDecoding];

可以利用归档来完成对象的深度复制

NSData *data = [NSKeyedArchiver archiveDataWithRootObject:dict];

NSDictionary *dicCopy = [NSKeyedArchiver unarchiveObjectWithData:data];

九:iOS应用开发入门

9.1 从iOS项目开始

Xcode工作区左侧的导航图标的快捷键是command+1/2;工作区右侧的视图图标的快捷键是command+option+1/2;对象库面板的快捷键是control+option+command+1;

每个Scene下边都有first response和View controller

9.2 MVC

MVC是所有面向对象程序设计语言都应该遵守的规范,MVC思想将一个应用分成三个基本部分:Model(模型),View(视图)和Controller(控制器),这三个部分以最少的耦合协同工作,从而提高应用的可扩展性和可维护性。

9.3 事件机制

程序获取控件的两种方式:1,通过IBOutlet获取 2,通过Tag属性获取

iOS应用常见的事件处理机制有三种 1,通过IBAction绑定控件的特定事件 2,通过程序为UI控件绑定事件 3,自带的delegate回调事件

9.4 storyboard控制UI界面

9.5 代码控制UI界面

-initWithFrame/-initWithCoder/-drawRect/-layoutSubviews/-didAddSubview/-willRemoveSubview/-willMoveToSuperview/-didMoveToSuperview/-willMoveToWindow/-didMoveToWindow/-touchesBegan:withEvent/-touchesMoved:withEvent/-touchesEnded:withEvent/-touchesCancelled:withEvent

9.6 美化iOS应用