iOS编程读书笔记

Posted zcube

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS编程读书笔记相关的知识,希望对你有一定的参考价值。

11,22,23,24,25,28暂时不需要看

1 第一个简单的ios应用

  • 单击按钮可以改变文字。

1.1 创建Xcode项目

  • 创建项目的时候Xcode会提供一些包含通用代码的模版,可以根据需要选择模版。
  • 创建项目是需要填写Organization Name和Company Identifier,也可以填入自己的公司名称和公司的反向域名。
  • Class Prefix在Xcode 7.2创建项目里面已经没有了,或许是因为默认创建的项目类太少,但是自己在创建类的时候还是加上前缀为好,因为OC没有命名空间。
  • 工作控件左侧是导航面板区域,中间是编辑区域。

1.2 模型-视图-控制器

  • 简单介绍了MVC,下图清晰阐述了MVC中各模块扮演的角色。

1.3 设计Quiz

  • 使用MVC思想,设计一个名叫Quiz的程序,实现单击按钮改变文字。
  • 下面的应用对象图,勾勒出了对象之间的相互关系。

1.4 创建视图控制器

  • 新版本Xcode会自动创建ViewController类了,且用storyboard文件来管理视图。
  • storyboard是多个xib文件集合的描述文件,也采用xml格式。那么storyboard与xib比较,区别在于:

    • 一个工程中可以有多个xib文件,一个xib文件对应着一个视图控制器和多个视图。而使用storyboard时,一个工程只需要一个主storyboard文件就可以了。
    • 在包含多个视图控制器的情况下,采用storyboard管理比较方便,而且storyboard还可以描述界面之间的导航关系。
  • Interface Builder一些介绍:

1.5 创建界面

  • 单击main.storyboard编辑视图,画布中间的视图比较宽,可以在右侧属性面板将Use Auto Layout勾选掉。
  • 通过Interface Builder在main.storyboard中添加Button和Label。
    • 构建项目时main.storyboard会被编译为NIB文件,然后Xcode会将NIB文件拷贝到应用程序包(bundle)中,其实就是应用程序以.app结尾的后缀。
    • 应用程序运行时会从程序包中按需载入NIB文件并激活文件中的对象。

1.6 创建关联

  • 通过connection,一个对象可以知道另一个对象在内存中的位置,从而使这两个对象可以协同工作。
  • Interface Builder中的两种关联:
    • outlets:指向对象的指针变量。
    • actions:动作方法,在视图对象和用户发生交互时会被调用。
  • 新版本Xcode创建项目使用storyboard所以没有File's Owner,可以通过打开Assistant editor方便的关联对象:

  • 创建关联在main.storyboard中的体现如下:

1.7 创建模型

  • ViewController对象创建完毕后会收到消息:initWithNibName:bundle:,所以可以在这里进行一些数据创建和初始化。

  • 关于代码自动补全功能:

    • 要实现模糊匹配可以安装FuzzyAutocomplete插件。
    • 自动补全后会有一些占位符,如果要使用占位符,可以按回车即可。

1.8 其它

  • AppDelegate应用程序委托是每个iOS应用都必须具备的启动入口。
  • 新版本Xcode不需要在委托中添加代码,如果按照书中添加代码,会出现白屏。
  • 模拟器中选择Simulator|Reset Content and Settings...可以将模拟器还原到默认设置并删除所有应用。

2 Objective-C

  • 开发iOS应用使用Objective-C和Cocoa Touch框架.

2.1 对象

  • Objective-C语言中,实例变量的变量名之前通常会加一个下划线,如_name,_date,_budget。
  • 调用某个对象的方法,可以向对象发送相应的消息(message)。

2.2 使用对象

  • 创建变量并进行初始化:Party *partyInstance = [[Party alloc] init];,将多个消息合并在一行的写法叫做嵌套消息发送(nested message send)。
  • 消息发送代码各组成部分:

  • 在Objective-C中,方法的唯一性取决于方法名,即使参数类型和返回类型不同,一个类也不能有两个名称相同的方法。

2.3 编写命令行工具PandomItems

  • 不能在快速枚举for in中添加或删除对象,否则抛出异常。
  • Objective-C格式字符串基本和C语言相同,%@对应的实参类型是指向任何一种对象的指针,通过覆盖description方法定义格式化输出。

2.4 创建Objective-C类的子类

  • Objective-C只允许单继承,所有的类都只能有一个父类。
  • Objective-C保留了C语言的关键字,并增加了特有的关键字,新的关键字都用前缀@加以区分。
  • Objective-C类中的存取方法名的规范为:
    • 存方法命名规则为英文单词set加上要修改的实例变量名,以_itemName为例,存方法名为setItemName:
    • 取方法名就是实例变量的变量名itemName,其它语言大多为:getItemName
  • #import#include的差别在于,#import可以确保不会重复导入同一个文件。
  • 使用点语法存取变量例如item.itemName编译后和发消息一样,也是调用之前写好的存取方法,所以存取方法名要按照规范书写。Apple官方代码坚持使用点语法存取实例变量。
  • 实例方法和类方法:调用实例方法时,需要向类的对象发送消息;调用类方法时,则向类自身发送消息。
  • 使用存取方法访问实例变量是良好的编程习惯,即使是访问对象自身的实例变量,也应该使用存取方法,但是在初始化方法中例外。

  • 初始化方法

    • 每个初始化方法以英文单词init开头,Objective-C中命名约定很重要,应该严格遵守。
    • 初始化方法的返回类型是instancetype,该关键字表示方法的返回类型和调用方法的对象类型相同。
    • instancetype引入之前,初始化方法返回类型是id,表示指向任意对象的指针,类似C语言的void*
  • instancetypeid
    • instancetype只能用来表示方法返回类型,id可以用来表示变量和方法参数类型。
    • id的定义是指向任意对象的指针,所以不需要再加*,比如:id item
  • 书中提到的指定初始化方法(designated initializer)不明白,根据书中后面的"其它初始化方法与初始化方法链的理解",指定初始化方法不同在于可以供其它初始化方法调用,但不调用其它初始化方法,通常参数最多。
  • selfsuper
    • self为类或对象自身,存在于方法中,是一个隐式(implicit)局部变量,相当于c++的this
    • super为父类,向super发消息,其实就是向self发消息,但是要求系统再查找方法时跳过当前对象的类,从父类开始查询。
  • 在初始化方法中应该直接访问实例变量,而不是使用存取方法。因为初始化方法执行时,无法确定新创建对象是否已经处于正确设置,所以应该直接访问类中实例变量。(其实这只是习惯问题)
  • 初始化方法总结的若干规则:

    • 类会继承父类所有的初始化方法,也可以加入其它初始化方法。
    • 初始化方法要直接或间接调用父类的指定初始化方法。
    • 其它初始化方法要直接或间接调用自身的指定初始化方法。
  • 类方法的声明和实例方法的声明差别在于第一个字符,实例方法为-,类方法为+

  • 在头文件中实例变量声明写在最前面,然后是类方法,接下来是初始化方法,最后是其它方法。这也是一种约定规范。
  • 在Objective-C中,如果某个类方法的返回类型是这个类的对象(例如:stringWithFormat:),就可以将该类方法称为便捷方法(convenience method)。

2.5 深入学习NSArray与NSMutableArray

  • Objective-C数组相关:
    • 可以存储不同类型继承自NSObject的对象指针,不能保存基本C类型变量。
    • 不能将nil加入数组,可以用NSNull代替,例如:[items addObject:[NSNull null]];
    • 访问数组可以使用下标语句NSString *foo = items[0];或发消息NSString *foo = [items objectAtIndex:0];,这两种方法效果是相同的。
  • 现在方括号的作用有3种:发送消息、存取方法、访问数组,如果使用点语法存取方法,下标语法访问数组,可以清晰突出发送消息代码。
  • NSMutableArray中,可以使用下标语法向数组中添加和修改对象,等价于insertObject:atIndex:replaceObjectAtIndex:withObject:发消息。

2.6 异常与未知选择器

对书中的疑惑:

  • 书中意思是说所有类对象都是运行时绑定,但是感觉并不是所有OC对象都是运行时(runtime)绑定,除了书中展示的使用id来接收创建的对象时,这时候书中所说的isa可能就不起作用了?

2.12 如何为类命名

  • OC没有提供命名空间机制,为了区分类,需要为类添加前缀。例如,开发一个MovieView应用,就可以在所有和项目相关的类名前加上MOV。
  • Apple提供的类名都为2个字符前缀,为了减少与Apple未来发布类产生冲突的可能,我们要使用至少3个字符前缀。

2.13 #import和@import

  • @import Fundation告诉编译器需要使用Foundation框架,之后编译器会优化预编译头文件和缓存编译结果过程,文件中不再明确引用框架,编译器会根据@import自动导入相应框架。
  • 目前只有Apple提供的框架可以使用@import,如果需要导入自己写的类和框架,只能使用#import

新版本的Xcode已经不会自动创建预编译头文件,因为预编译头文件会带来代码复用困难等问题。

3 通过ARC管理内存

3.1 栈

  • 执行方法或函数是从内存栈(stack)中分配空间,每块空间称为帧(frame),用来保存方法内声明的变量值。
  • 调用main函数时栈的变化过程如下图:

3.2 堆

  • 堆(heap)是内存中另一块区域,和栈是分开的。
  • 栈和堆区别是:栈按后进先出规则保存一组帧,堆则包含了大量无序的活动对象,需要通过指针来访问。

  • 发送alloc消息是从堆上分配内存。

  • iOS应用通过ARC来自动完成堆内存管理工作。

3.3 指针变量与对象所有权

  • 如果堆内存中对象,没有指针指向它的话就会被释放掉,系统会自动记录有多少对象指针引用它,1个引用ARC就为1,2个为2,0个内存会被释放。
  • NSObject实现了一个名为dealloc的方法,当某个对象即将被释放时,程序会调用该方法。

3.4 强引用与弱引用

  • 只要指针变量指向了某个对象,那么相应的对象就会多一个引用计数,并且不会被释放。这种指针特性称为强引用(strong reference)。
  • 也可以选择让指针变量不影响某指向对象的引用计数,这种不会改变对象拥有者个数的指针特性称为弱引用。
  • 弱引用用来解决强引用循环问题(strong reference cycle,也称保留循环),当两个以上对象相互之间有强引用时就回产生强引用循环。

强引用循环问题

  • 存在强引用循环问题如下图:

  • 图中两个BNRItem对象中包含两个指向BNRItem对象的指针_container和_containerItem互相指向彼此。

  • 当items设置为nil后,没有两个BNRItem对象引用计数减1,但是互相依然强引用,所以内存无法释放,如下图:

解决强引用问题

  • 要解决上面的强引用循环问题,需要将新创建的两个BNRItem对象之间的某个指针改为弱引用。
  • 大部分强引用循环可以确定一个父子关系,父对象使用具有强引用特性的指针,指向子对象。子对象使用弱引用特性指针,指回父对象。这样就可以避免强引用循环问题。
  • 将上面的_container设为弱引用,如:__weak BNRItem *_container;,这样就解决了强引用循环问题,如下图:

3.5 属性

  • 属性相当于:声明实例对象+相应存取方法。它们的等价表如下:

  • 表中都具有一个实例变量_name和一对存取方法,右边只需要一个属性就完成了。
  • 如果声明一个名为itemName的属性,编译器会自动生成实例变量_itemName、取方法itemName和存方法setItemName:

  • 自定义属性存取方法:

    • 如果覆盖了存取方法(或为只读属性覆盖了取方法),编译器就不会自动创建相应变量了,如果需要实例变量就需要明确声明。

属性的特性

  • 任何属性都有一组特性,如:@property (nonatomic, readwrite, strong) NSString *itemName;
  • 多线程特性:
    • 两种可选类型nonatomicatomic,通常设为nonatomic
  • 读/写特性:
    • 两种可选类型readwritereadonly,如果时readonly只会生成取方法。
  • 内存管理特性:
    • 有4种可选类型:strongweakcopyunsafe_unretained.
    • 对于需指向非对象属性,如:int,默认会选用unsafe_unretained,不做内存管理。
    • 当属性是可变子类对象(例如,NSString/NSMutableString或NSArray/NSMutableArray)指针时,应设置copy特性。因为可变子类有可能被其它引用者修改,所以会复制一个新的对象给属性。

4 视图与视图层次结构

4.1 视图基础

  • 视图是UIView对象,或是UIView子类对象。
  • 视图可以处理事件,例如触摸。
  • 视图会按层次结构排列,位于视图层次结构顶端的是应用窗口。

4.2 视图层次结构

  • 任何一个应用都只有一个UIWindow对象,负责包含应用中所有视图,视图还可以有自己的子视图。
  • 视图层次结构构成应用的界面:

  • 视图会将自己绘制到layer上,然后组合起来绘制到屏幕上,每个UIView对象又一个layer属性,指向一个CALayer类对象。

4.3 创建UIView子类

  • 新版本Xcode创建的项目使用ViewController管理视图,如果要实现书中画红色矩形需在viewDidLoad中添加如下代码:

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    CGRect firstFrame = CGRectMake(160, 240, 100, 150);
    BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];
    firstView.backgroundColor = [UIColor redColor];
    [self.view addSubview:firstView];


    CGRect secondFrame = CGRectMake(20, 30, 50, 50);
    BNRHypnosisView *secondView = [[BNRHypnosisView alloc] initWithFrame:secondFrame];
    secondView.backgroundColor = [UIColor blueColor];
    [firstView addSubview:secondView];


4.4 在drawRect:方法中自定义绘图

Xcode使用lldb调试: