从零开始的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中的类、方法、属性的内容,为我们接下来的面向对象的三个特征建立好基础。这三个内容我们留到下篇再谈(考试周更新不能存在的)。


 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

与 Dian 的连接断开,我们正在尝试重连,请耐心等待