零、关于快速学习ios开发系列文章

为什么会要写这个系列?

这是个好问题,其实我也不知道这个系列是否会和其他系列一样写着写着就搁置好多了,然后不知道什么时候才更新。但是无所谓,因为本来就是主要用来记录个人学习过程的,如果在这过程中能够帮助到别人也算是一件不错的事情。所以不要太期望文章一定会及时或者持续更新下去,就比如博客中其他文章一样,因为很多也只是记录个人学习历程,如果某个技术在实际工作或者学习中不需要继续深究下去了,可能就不会及时持续更新了,因为要忙的事情实在太多,当然,如果有时间的话,我还是非常希望能把未完结的所有系列文章都给来个大结局。这不,最近入手了Mac,当然得学习学习ios了。如果你也是新手,可以跟着一起玩玩。

一、需要准备的

  • 一台Mac
  • Mac里装个Xcode,这里版本是6.1.1
  • 一只会编程的猴子

上述三个条件,前面两个应该都比较好搞定,第三个需要一个会编程的猴子,这个条件就比较特殊了,因为每只猴子的基础都不一样啊,什么?你不知道猴子是什么?那估计你不需要往下看了。当然猴子的基础越好,就越能掌握本系列的精髓-快速。所以,在学习过程中绝对不是那种《xxx入门》什么类型的,会花很多时间先来学学oc语言语法,然后一步一步截图展示如何创建一个hello world。所以做好准备,可能在学习过程中,你会需要另外去查阅资料。

二、从xxx语言到Objective-C

在ios开发中现在可以使用Objective-C或者是Swift开发语言。这里学习为什么不选Swift呢?虽然她比较新,而且相信未来发展也是非常不错的,但是目前第三方支持或者一些坑可能都没有前人踩过,所以还是选择稳定且但比较旧的Objective-C。当然,对于像笔者这样喜欢尝试各种语言的,到时候切换Swift也说不会有任何困难的。所以,这个标题也就变成了xxx语言到Objective-C了,因为笔者并不是从某一种语言转来的,而是一堆。所以我会在不同语言角度来看Objective-C的语法来对比,当然还是会选择一些比较常用的语言。 所以如果你还没有学过其他编程语言,可能就比较惨了,因为快速入门是建立在之前基础上的,建议还是乖乖的先学习一门语言并熟练运用再回来,不然看了也说浪费时间。

三、快速浏览Objective-C

既然要快速学,那我们肯定不是去拿本Objective-C的基本语法书从Hello World开始学起,于是我们就站在已经学会的角度去学,听起来有点怪怪的。首先我们来回答个问题,为什么学Objective-C?很明显,我们要拿它来写ios的应用或者游戏,于是,我们就清楚我们要做的了。当然说赶紧的打开Xcode,创建第一个项目。如下图:

按照上创建FirstApp,并设置项目名称等信息,然后可以就可以看下项目的结构了:

于是我们从目录结构来猜猜看,马上发现有个main.m的文件,学过C语言的应该有点印象,莫非它也是oc的入口函数,二话不说,打开之:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

好家伙,连main函数参数都和C语言的一样。那来找找不一样的呢,发现开头是#import而不是#include,他们具体异同点如下:

  • #import是一个预处理指令,作用跟C语言的#include类似,包含某个文件的内容到预处理指令所在的位置。
  • 在C\C++中,我们用#include来包含头文件,但是同一个头文件可能被包含多次。为了解决这个问题,一般我们会这么写:

    #ifndef APP_H #define APP_H

    /…../

    #endif

  • 使用#import来包含头文件,可以自动防止同一个头文件被包含多次。

  • #import 表示包含系统自带的文件,#import “xxx”表示包含开发人员自己创建的文件

我们再来看main函数体的内容,发现有个@autoreleasepool,这个是什么东西?写过Java的都应该知道Java的垃圾回收机制,但是OC是不支持垃圾回收的,需要开发人员编写代码来释放对象所占用的内存。这个东西就是OC内存管理的一种东西-自动释放池,使用这个东西就可以方便开发人员不再需要每次手动的retain和release对象,这部分涉及到内存管理比较深入的东西了,暂且不深入了解,后续再说。

四、UIApplicationMain

我们打开UIApplicationMain的定义

UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

嗯,看起来像是一个函数,但是前面有个UIKIT_EXTERN,继续查看源码:

#import <Availability.h>

#ifdef __cplusplus
#define UIKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
#else
#define UIKIT_EXTERN            extern __attribute__((visibility ("default")))
#endif

#define UIKIT_STATIC_INLINE     static inline

原来是一个宏定义,其中cplusplus是cpp中的自定义宏,如果这是一段cpp的代码,那么加入extern”C”和其中的代码。extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。C++之父在设计C++之时,考虑到当时已经存在了大量的C代码,为了支持原来的C代码和已经写好C库,需要在C++中尽可能的支持C,而 extern “C”就是其中的一个策略。attribute是GNU C的一种机制,用法为_attribute ((attribute-list))。当项目需要作为一个库被外包引用的时候通常在编译时可以用参数-fvisibility指定所有符号的可见性。在编译命令中加入 -fvisibility=hidden参数,会将所有默认的public的属性变为hidden。此时,如果对函数设置attribute((visibility (“default”)))参数,使特定的函数仍然按默认的public属性处理,则-fvisibility=hidden参数不会对该函数起作用。所以,设置了-fvisibility=hidden参数之后,只有设置了attribute((visibility (“default”)))的函数才是对外可见的。

上面讲了一大堆,总之呢,就是UIApplicationMain是界面相关的UIKit框架对外可见的一个函数。

再来看看UIApplicationMain函数,它接收四个参数,其中argc和argv是main函数传过来的,该函数还需要两个字符串参数,用于标识应用程序的首要类(即应用程序对象所属的类)和应用程序委托类。果首要类字符串的值为nil, UIKit就缺省使用UIApplication类;如果应用程序委托类为nil,UIKit就会将应用程序主nib文件(针对通过Xcode模板创建的应用程序)中的某个对象假定为应用程序的委托对象。在这个例子中,应用程序委托类不是nil的,从之前的函数参数类型和参数名称来看,是自定义一个字符串类型的代理类名,但是是这样的:

NSStringFromClass([AppDelegate class])

打开NSStringFromClass定义看到:

FOUNDATION_EXPORT NSString *NSStringFromClass(Class aClass);

这是FOUNDATION框架中提供的一个底层对外可见的函数,看意思应该是获取一个Class的名称。至于FOUNDATION和UIKIT框架,这里先不详细介绍了,后面准备讲整个ios开发框架架构时候再说。那么里面这个

[AppDelegate class]

是什么意思?这是OC中方法调用的一种语法,其实OC调用方法是使用“消息结构”(messaging structure)而非C++等语言的“函数调用”(function calling),关键区别在于:使用消息结构的语言,其运行时所应执行的代码由运行环境来决定;而使用函数调用的语言,则由编译器决定。因此,OC是相当动态的,当调用一个实例的方法,在runtime时向该实例的指针发送消息,实例在收到消息后,从自身的实现中寻找响应这条消息的方法。基本语法如下:

[实例 方法]; 

or

[类名 方法名];

前面讲过调用一个类或实例的方法,实际上是给这个类或实例发消息(message)。类或实例称为“接收方”。所以,调用方法的格式也可以理解为:

[接收方 消息];

在术语上,整个表达式也叫消息表达式。如果有返回值,那么如下:

变量=[接收方 消息];

如果要传递参数呢:

[Dog setName:“tom”];

当然如果有多个参数:

[接收方 名字1:参数1 名字2:参数2, 名字3:参数3 .. ];

为了避免声明过多的本地变量保存临时结果,Objective-C允许你使用嵌套消息。每个嵌套消息的返回值可以作为其他消息的参数或者目标。如下:

[NSString stringWithFormat:[dog getName]];

虽然这样很方便,但是为了更好的代码可读性,建议避免在一行代码中嵌套调用超过两个方法。

介绍了那么多关于关于消息传递的知识,现在终于可以理解

[AppDelegate class]

其实意思就是向AppDelegate类发了class消息,那么这个消息(可以理解为一个方法调用)是什么呢?我们继续找到class的定义:

+ (Class)class;

在NSObject.h文件中找到了如上的声明,有点类似c++中头文件中方法的声明。此处又出现奇怪的+号,这个又是什么呢?请听下回分解。

##文档信息