从零开始的iOS开发之旅:Objective-C篇(中)
-
从零开始的iOS开发之旅:Objective-C篇(中)
by
张新驿
前言
在上一篇博客从零开始的iOS开发之旅:Objective-C篇(上)中,我们主要讲了ObjC的一些基础知识,以及ObjC面向对象的概括。本篇博客主要是讲述ObjC的面向对象的实际使用。(拖延症晚期)
第三方工具
- CocoaPods(便利的第三方库管理器)
- AppCode(JetBrains家的iOS应用IDE,写代码上比Xcode体验好太多,但不支持InterfaceBuilder,没法设计UI)
Objective-C的面相对象
同上一篇说讲的一样,ObjC的面向对象语法源于Smalltalk消息传递风格,同我们所熟悉的C++或Java的面向对象不同。但是其思想是一致的,即
封装
、继承
、多态
。类
如同所有其他的面向对象语言,类是 Objective-C 用来封装数据,以及操作数据的行为的基础结构。对象就是类的运行期间实例,它包含了类声明的实例变量自己的内存拷贝,以及类成员的指针。Objective-C 的类规格说明包含了两个部分:
定义(interface)
与实现(implementation)
。定义(interface)
部分包含了类声明和实例变量的定义,以及类相关的方法。实现(implementation)
部分包含了类方法的实际代码。类的定义文件遵循C语言之惯例以.h为后缀,实现文件以.m为后缀。
下面展现了声明一个叫做
MyClass
的类的语法,这个类继承自NSObject
基础类。类声明总是由@interface
编译选项开始,由@end
编译选项结束。类名之后的(用冒号分隔的)是父类的名字。类的实例(或者成员)变量声明在被大括号包含的代码块中。实例变量块后面就是类声明的方法的列表。每个实例变量和方法声明都以分号结尾。@interface MyObject : NSObject //大括号中为该类的成员变量 { int memberVar1; double memberVar2; NSString *memberVar3; } - (void)instance_method:(NSString *)aString;//实例方法 + (void)class_method;//类方法 @end
Interface
定义部分,清楚定义了类的名称、数据成员和方法。 以关键字@interface作为开始,@end作为结束。
下面为Interface的定义方法@interface MyObject : NSObject //该类继承了NSObject类 { int memberVar1; // 实体变量 id memberVar2; } +(return_type) class_method; // 类方法 -(return_type) instance_method1; // 实例方法 -(return_type) instance_method2: (int) p1;//单参数方法 -(return_type) instance_method3: (int) p1 andPar: (int) p2;//多参数方法 @end
方法前面的 +/- 号代表函数的类型:加号(+)代表
类方法(class method)
,不需要实例就可以调用,与C++/Java 的静态函数(static member function)
相似。减号(-)即是一般的实例方法(instance method)
。这里提供了一份意义相近的C#语法对照,如下:
class MyClass:SuperClass { protected int memberVar1; protected object memberVar2; public static return_type class_method(); // 类方法 public return_type instance_method1(); // 实例方法 public return_type instance_method2(int p1); public return_type instance_method3(int p1, int p2); }
Objective-C定义一个新的方法时,名称内的冒号(:)代表参数传递,不同于C语言以数学函数的括号来传递参数。Objective-C方法使得参数可以夹杂于名称中间,不必全部附缀于方法名称的尾端,可以提高程序可读性。设定颜色RGB值的方法为例:
- (void) setColorToRed: (float)red Green: (float)green Blue:(float)blue; /* 声明方法*/ [myColor setColorToRed: 1.0 Green: 0.8 Blue: 0.2]; /* 调用方法*/
这个方法的签名是
setColorToRed:Green:Blue:
。每个冒号后面都带着一个float类别的参数,分别代表红,绿,蓝三色Implementation
实现区块则包含了公开方法的实现,以及定义私有(private)变量及方法。 以关键字@implementation作为区块起头,@end结尾。
@implementation MyObject { int memberVar3; //私有变量 } +(return_type) class_method { .... //method implementation } -(return_type) instance_method1 { .... } -(return_type) instance_method2: (int) p1 { .... } -(return_type) instance_method3: (int) p1 andPar: (int) p2 { .... } @end
不只Interface区块可定义实体变量,Implementation区块也可以定义实体变量,两者的差别在于访问权限的不同,Interface区块内的实体变量默认权限为protected,宣告于implementation区块的实体变量则默认为private,故在Implementation区块定义私有成员更匹配面向对象之封装原则,因为如此类别之私有信息就不需曝露于公开interface(.h文件)中。
创建函数(构造函数)
Objective-C创建对象需通过alloc以及init两个消息。alloc的作用是分配内存,init则是初始化对象。 init与alloc都是定义在NSObject里的方法,父对象收到这两个信息并做出正确回应后,新对象才创建完毕。以下为范例:
MyObject * my = [[MyObject alloc] init];
在Objective-C 2.0里,若创建对象不需要参数,则可直接使用new
MyObject * my = [MyObject new];
仅仅是语法上的精简,效果完全相同。
若要自己定义初始化的过程,可以重写init方法,来添加额外的工作。(用途类似C++ 的构造函数constructor)
方法
让我们看一下上一节
@interface
里几行像C语言中的函数原型- (void)instance_method:(NSString *)aString; + (void)class_method;
在Obj-C中,他们被称为方发声明(method declaration)。他们看起来像C中的函数原型,用于说明“我们所支持的功能”。方法声明中列出了函数的名称、参数、返回值以及类型。
下面是方发声明的格式-(return type)methond:(argument type)arg1:(argument type)arg2;
上面的最前面的
-
表示这是Obj-C方法的声明。这是区分方发声明与函数原型的一种方式,+
代表类方法(或者说叫做静态方法),-
代表实例方法。
在后面的圆括号中,表示该方法的返回值。Obj-C方法可以和C函数一样的返回值类型:标准类型、指针、引用对象以及结构体。
在方法名之后的:
表示该方法的参数,参数之间以:
隔开并且必须注明参数类型。
####中缀符
Obj-C中支持一种名为中缀符的语法技术。方法名称及其参数都是合在一起的。例如以下面这个方法-(void)setTextValue:(NSString *)textValue andTextColor:(NSString *)textColor;
及其调用
[test1 setTextValue:@"Hello World" andTextColoe:@"red"];
setTextValue:
与andTextColor:
是参数的名称(其实是方法的名称的一部分),@"Hello World"
,@"red"
是被传递的参数。
而在C/C++中,所有参数都在函数名之后,如下面void setTextValueandTextColor("Hello World","red");
尽管乍一看有些古怪,但其使代码更具可读性,参数的含义更容易被理解。
属性
属性是用来代替声明存取方法的便捷方式。属性不会在你的类声明中创建一个新的实例变量。他们仅仅是定义方法访问已有的实例变量的速记方式而已。暴露实例变量的类,可以使用属性记号代替getter和setter语法。类还可以使用属性暴露一些“虚拟”的实例变量,他们是部分数据动态计算的结果,而不是确实保存在实例变量内的。
实际上可以说,属性节约了你必须要写的大量多余的代码。因为大多数存取方法都是用类似的方式实现的,属性避免了为类暴露的每个实例变量提供不同的getter和setter的需求。取而代之的是,你用属性声明指定你希望的行为,然后在编译期间合成基于声明的实际的getter和setter方法。
属性声明应该放在类接口的方法声明那里。基本的定义使用@property编译选项,紧跟着类型信息和属性的名字。你还可以用定制选项对属性进行配置,这决定了存取方法的行为。下面的例子展示了一些简单的属性声明:
@interface Person : NSObject { NSString *name; int age; } @property (copy) NSString *name; @property (nonatomic,assign) int age; @end
属性的访问方法由@synthesize关键字来实现,它由属性的声明自动的产生一对访问方法。另外,也可以选择使用@dynamic关键字表明访问方法会由程序员手工提供。
@implementation Person @synthesize name,age;//@synthesize为自动生成对应方法,@dynamic来手动提供方法 @end
属性可以利用传统的消息表达式、点表达式或"valueForKey:"/"setValue:forKey:"方法对来访问。
Person *person1=[[Person alloc] init]; person1.name = @"Zhang";//可以通过.直接访问,相当于[person1 setName:@"Zhang"]; [person1 setAge:20]; NSLog(@"%@ is %d",person1.name,[person1 age]);//可以通过.或对应方法来获取数据,这里的age并非成员变量,而是属性对应的方法
总结
这一篇主要是谈及了Obj-C中的类、方法、属性的内容,为我们接下来的面向对象的三个特征建立好基础。这三个内容我们留到下篇再谈(考试周更新不能存在的)。
-
在线等更新
-
发现一个typo
[test1 setTextValue:@"Hello World" andTextColoe:@"red"];
↓
[test1 setTextValue:@"Hello World" andTextColor:@"red"];