1. iOS 系统结构
iOS是基于Unix的系统,整个系统可以粗略的分为四层。分别是Core OS层,Core Services层,Media层以及Cocoa Touch层。
Core OS 层:
Core OS 层主要负责底层相关的功能和服务,例如底层Socket通信,文件系统访问,安全,电源管理等。当然还有Unix Kernel.这层主要是为上层提供服务,所以一般情况下我们不会使用到。相当于Android中的内核和CPP、C层。
Core Services
Core Services层包含手机中的主要服务,如集合(数组,List,Collection),位置服务,网络服务,数据库等。相当于Android中的Framework层,提供各种API供上层使用。
Media
Media层与Core Services层其实差不多,只是iOS中把Media Service单独分层出来提供服务。Media层提供包括Audio,Video,OpenAL,OpenGL,图片,文档等API。
Cocoa Touch
Cocoa Touch 层主要负责用户操作,UI,View等直接与End User打交道的部分。简单的讲就是用户使用手机的时候可以真实感受或者看到的部分.
这一层也是我们编程时会大量使用,甚至主要使用的部分。因此在学习iOS开发的过程中,我们对这一层应该十分注意。
2. MVC 架构
iOS开发中,我们需要使用到的开发模式是MVC模式。MVC即Model,View,Controller。这种开发方式把数据和显示分开,使得同一种数据可以以各种各样的方式展现给用户。而我们需要改动展现方式的时候并不需要改动到Model层的内容。
MVC已经是现在比较流行的设计模式,从大型网站到小型移动APP,都可以看到MVC。实际上,Andoird开发中也是使用的MVC Pattern。
在MVC中各个模块分工明确,合作紧密,保证了我们的代码正确的运行,易于维护和修改。同时具有良好的复用性以及很低的偶合度。
上图中展现了MVC中各个模块之间的通信方式,其中,Controller可以无限制的与Model和View通信——当然了,Controller需要从Model层拿到数据,并告诉View层如何显示这些数据。图中红色的箭头表明,Model与View之间是绝对不能相互通信的,这样做是为了降低模块间的偶合度,方便修改和维护。
另外,图片中的双黄线(道路上的双黄线一样),也表明Model是绝对不能跨过双黄线与View有关系的。其中有点难以理解的是Model与Controller以及View与Controller之间的线是实线和虚线混合。虚线当然表示,Controller可以跨过。实现部分我们下面会讲到。
Model=What?
MVC中的Model,即数据模型,是程序中对现实世界中的问题域的建模,可以表示一辆车,一个人,一本书。但是它只是一个数据结构,只负责保存数据,保证与现实世界中实物的描述。只表示What。
Model并不会直接与Controller或者View通信,你需要不需要它,它都在那里,不增不减不变化。这样就很好的把View和Model分离,使得我们的程序简洁易懂且易维护。
Model与Controller通信
前面有讲到,Model与Controller之间是用实线表示,这表明Model并不能随意的访问Controller。但是有时候我们的Controller是需要接收Model层的消息的,比如我们同时有两个Controller C1和C2,C1正在向用户显示数据库中所有的Model(可以想像成书),C2是图书管理员,正在把书借出支一本。这时候,C2改变了Model中的内容,Model就需要告诉Controller,Oh,我这边的书借出去一本了,你得不显示那本书了。
在MVC模式中,要实现Model层到Controller的通信,我们使用一种类似广播的方式(是不是很熟悉?Android中的Broadcast)。Model中数据变化时,Model会发出一条广播(Hi,to whom may concerned,I’ve changed),然后对这个Model感兴趣的Controller就会收到这个广播并告诉对应的View改变显示方式。
Controller=How the “what” shows on UI.
MVC中的Controller,即控制器,控制着整个程序的逻辑和Model如何显示到View层。Controller把Model和View连接起来,让我们可以在View上看到Controller想要Model层显示的样子。例如,我们在Model存在一个书箱的List,Controller可以控制这个List以书架的形式显示到View层,也可以以Table的形式显示到View层。
View = Your Controller’s minions, Highly re-useable.
MVC中的View层只负责显示以及告诉Controller用户的操作。这一部分是可以高度重用的。例如,同样是一个Button我们可以显示到这个APP里面,也可以在另一个APP里面使用。这一层的大部分UI控件Apple都有提供默认实现。当然我们也可以构造自己的View以用更酷的方式来展现我们的数据。
View与Controller间的通信
Action -> Target方式
在程序运行的过程中,View层其实是需要与Controller通信的,比如用户点击了OK这个Button,View就需要告诉Controller“Hi,用户点击了OK这个Button,我该怎么办?” .当然View层不可能直接调用Controller的某个方法来处理用户点击这个事件,因为View不知道该使用Controller中的哪个方法。
因此我们使用到一种叫做Target的方式来解决这个问题,Controller会事先告诉View,“Hey,如果有人点击了OK,你就叫我运行okButtonClicked()这个方法吧。”。这下问题就解决了,有人点击了OK以后,View就会把这个动作转给Target(即Controller事先告诉View的那个方法)。然后Controller运行完该方法,处理好这个事件以后就会告诉View,好了,我知道了,你该这样,如此,这般的显示就好了。
Delegate方式
View与Controller之间通信还会有另一种情况。假设View是一个ScrollView,当用户在ScrollView上滑动的时候,View会想知道:我应该让用户滑动这个View吗?怎么滑动?这个时候,我们就需要用到代理了。View把类似:Should,Will,did这类问题交给Controller代理,即遇到这样的问题时,View直接交给Controller处理。
3. Objective-C 以及 Model of Card source(a card game)
Objective-C
- Objective-C是CPP的一个超集,即Objective-C包含了CPP中的所有特性,但又添加了一些CPP中所不具有的特性。
- Objective-C中只有单继承,不支持多继承。
- Objective-C中没有GC(垃圾回收机制),所有的对象都存在于堆中(不在栈中),我们需要自己回收不再需要的Objects。
> all objects lives in heap, not in stack.
No GC in Objective-C.Reference counting to clear the un-reference Object. - Objective-C中的垃圾回收机制是使用的Reference Count机制,当某个对象不再被某个指针引用,就表明这个对象不再被需要,就会被回收。在早期的iOS系统中程序员需要自己维护这个Reference Count,现在这些动作被系统处理了。
在继续讲下去之前,先贴一个Card的代码
在Objective-C中每个对象都会有.h和.m两个部分,.h与CPP中的.h一样,向外部暴露接口。.m中则是实际的私有实现。
以下是对前面代码的一些简单解释(复杂的我也不懂,现学现卖)
- Card.h
#import <Foundation/Foundation.h>
import了基础包,实际上,我们的开发中几乎都要import这个模块,因为这里面包含了所有的基础Objects。
@interface Card:NSObject
即声明了一个名为Card的类,Objective-C中声名类的方式与Java中有很大的不同,语法方面的问题大家只能死记硬背了… 其中冒号后面跟了一个NSObject表明Card是继承自NSObject的。NSObject相当于Java中的Object类,基本上是所有Object的基类。
@property (strong, nonatomic) NSString *contents;
@property (nonatomic, getter=isFaceUp) BOOL faceUp;
@property (nonatomic) BOOL unplayable
这几行代码声明了Card的一系列Property,不像Java中的成员变量这样的东西。Objective-C中使用property来表示。我们需要设置或者取出某个property的值的时候,会用到getter和setter来访问。而真实的数据是存在私有变量中,没有办法直接访问的。
strong/weak pointer
(暂时还没有搞清楚,应该和Java中的强引用和弱引用相关,用于GC的时候~)
nonatomic: no thread safe
nonatomic表示这个property不是线程安全的,所以系统不会对这个property加上一系列的锁,这样会减少运行时的消耗。如果我们的property不需要线程安全,都应该加上这个修饰关键字。
properties (getters & setters)
前面有讲到Objective-C中并没有成员变量这样的说法,一个类中的所有数据都是以property的形式存在的。这样的好处是每个property都有自己的getter和setter,我们可以控制其它类获取这个数据的过程。
右边.m的部分中有这样的代码:
- (BOOL)isFaceUp
{
return _faceUp;
}
- (void) setFaceUp:(BOOL)faceUp
{
_faceUp=faceUp;
}
- (BOOL)unplayable
{
return _unplayable;
}
- (void)setUnplayable:(BOOL)unplayable
{
_unplayable = unplayable;
}
这段代码其实是在现实中我们不会看到的,这个会是编译器自动生成的Getter和Setter。
默认情况下,生成的getter的名字就是使用的我们声明的property的名字。setter的名字则相对复杂,默认名字是setProperty,其中Property就是我们声明的property名字首字母大写(所以声明property的时候我们要以小写字母开头~)
另外,我们可以个性getter的名字,如下面这段代码把getter的名字改成了isFaceUp,以更符合英语中的语法习惯。
@property (nonatomic, getter=isFaceUp) BOOL faceUp;
第一篇就写到这里了,本人菜鸟,边听着没有字幕的Stanford公开课边写下这些东西。各位看官请轻拍,有任何建议欢迎评论。欢迎访问我的个人页面:http://1.pingoflove.sinaapp.com/?p=44