zoukankan      html  css  js  c++  java
  • object-c语法

    Objective-C:C的超集

    Objective-Objective-C是C语言的严格超集--任何C语言程序不经修改就可以直接通过Objective-C编译器,在Objective-C中使用C语言代码也是完全合法的。Objective-C被描述为盖在C语言上的薄薄一层,因为Objective-C的原意就是在C语言主体上加入面向对象的特性。

    第一个 Objective-C 程序,基于Xcode 4.3.1:

    #import <Foundation/Foundation.h>
    
    int main(int argc, char *argv[]) {
    
        @autoreleasepool {
            NSLog(@"Hello World!");
        }
    
       return 0;
    }

    消息传递

    C++里,送一个消息给对象(或者说调用一个方法)的语法如下:

    obj.method(argument);

    Objective-C则写成:

    [obj method: argument];

    此二者并不仅仅是语法上的差异,还有基本行为上的不同。

    这里以一个汽车类(car class)的简单例子来解释Objective-C的消息传递特性:

    [car fly];

    典型的C++意义解读是"调用car类别的fly方法"。若car类别里头没有定义fly方法,那编译肯定不会通过。但是Objective-C里,我们应当解读为"发提交一个fly的消息给car对象",fly是消息,而car是消息的接收者。car收到消息后会决定如何回应这个消息,若car类别内定义有fly方法就运行方法内之代码,若car内不存在fly方法,则程序依旧可以通过编译,运行期则抛出异常。

    此二种风格各有优劣。C++强制要求所有的方法都必须有对应的动作,且编译期绑定使得函数调用非常快速。缺点是仅能借由virtual关键字提供有限的动态绑定能力。Objective-C天生即具备鸭子类型之动态绑定能力,因为运行期才处理消息,允许发送未知消息给对象。可以送消息给整个对象集合而不需要一一检查每个对象的类型,也具备消息转送机制。同时空对象nil接受消息后默认为不做事,所以送消息给nil也不用担心程序崩溃。

    字符串

    Objective-C提供了一个助记符可以方便地从常量值创建NSString对象。要使用这个助记符,你需要做的全部事情,是在普通的双引号字符串前放置一个@符号,如下面的例子所示:

    NSString* myString = @"My String
    ";
    NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"];
    
    // 从一个C语言字符串创建Objective-C字符串
    NSString*  fromCString = [NSString stringWithCString:"A C string" 
    encoding:NSASCIIStringEncoding];

    Objective-C 的类规格说明包含了两个部分:定义(interface)与实现(implementation)。定义(interface)部分包含了类声明和实例变量的定义,以及类相关的方法。实现(implementation)部分包含了类方法的实际代码。

    下图展现了声明一个叫做 MyClass 的类的语法,这个类继承自 NSObject 基础类。类声明总是由 @interface 编译选项开始,由 @end 编译选项结束。类名之后的(用冒号分隔的)是父类的名字。类的实例(或者成员)变量声明在被大括号包含的代码块中。实例变量块后面就是类声明的方法的列表。每个实例变量和方法声明都以分号结尾。

    类的定义文件遵循C语言之惯例以.h为后缀,实现文件以.m为后缀。

    类声明图

    Interface

    定义部分,清楚定义了类的名称、数据成员和方法。 以关键字@interface作为开始,@end作为结束。

    @interface MyObject : NSObject {
        int memberVar1; // 实体变量
        id  memberVar2; //访问权限默认为protected
    }
    
    +(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++ 的静态函数(static member function)相似.

    减号(-)即是一般的实例方法(instance method)。

    这里提供了一份意义相近的C++语法对照,如下:

    class MyObject : public NSObject {
    protected:
        int memberVar1;  // 实体变量
        void * memberVar2;
    
      public:
        static return_type class_method(); // 类方法(静态方法)
    
        return_type instance_method1();    // 实例方法
        return_type instance_method2( int p1 );
        return_type instance_method3( int p1, int p2 );
    }

    Objective-C定义一个新的方法时,冒号(:)代表参数传递

    - (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; //访问权限默认为private
    }
    
    +(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区块内的变量默认权限为protected,声明于implementation区块的变量则默认为private

    创建对象

    Objective-C创建对象需通过alloc以及init两个消息。alloc的作用是分配内存,init则是初始化对象。 init与alloc都是定义在NSObject里的方法

    MyObject * my = [[MyObject alloc] init];

    在Objective-C 2.0里,若创建对象不需要参数,则可直接使用new

    MyObject * my = [MyObject new];

    方法

    方法声明:

     调用方法:

    消息被中括号( [  ] )包括。中括号中间,接收消息的对象在左边,消息(包括消息需要的任何参数)在右边。例如,给myArray变量传递消息insertObject:atIndex:消息,你需要使用如下的语法:

    [myArray insertObject:anObj atIndex:0];

    为了避免声明过多的本地变量保存临时结果,Objective-C允许你使用嵌套消息。每个嵌套消息的返回值可以作为其他消息的参数或者目标。例如,你可以用任何获取这种值的消息来代替前面例子里面的任何变量。所以,如果你有另外一个对象叫做myAppObject拥有方法,可以访问数组对象,以及插入对象到一个数组,你可以把前面的例子写成如下的样子:

    [[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];

    虽然前面的例子都是传递消息给某个类的实例,但是你也可以传递消息给类本身。当给类发消息,你指定的方法必须被定义为类方法,而不是实例方法。你可以认为类方法跟C++类里面的静态成员有点像(但是不是完全相同的)。

    下面的例子演示了一个类方法如何作为类的工厂方法。在这里,arrayWithCapacity是NSMutableArray类的类方法,为类的新实例分配内容并初始化,然后返回给你。

    NSMutableArray*   myArray = nil; // nil 基本上等同于 NULL
    
    // 创建一个新的数组,并把它赋值给 myArray 变量
    myArray = [NSMutableArray arrayWithCapacity:0];

    属性

    属性是用来代替声明存取方法的便捷方式。属性不会在你的类声明中创建一个新的实例变量。他们仅仅是定义方法访问已有的实例变量的速记方式而已。暴露实例变量的类,可以使用属性记号代替getter和setter语法。类还可以使用属性暴露一些“虚拟”的实例变量,他们是部分数据动态计算的结果,而不是确实保存在实例变量内的。

    实际上可以说,属性节约了你必须要写的大量多余的代码。因为大多数存取方法都是用类似的方式实现的,属性避免了为类暴露的每个实例变量提供不同的getter和setter的需求。取而代之的是,你用属性声明指定你希望的行为,然后在编译期间合成基于声明的实际的getter和setter方法。

    属性声明应该放在类接口的方法声明那里。基本的定义使用@property编译选项,紧跟着类型信息和属性的名字。你还可以用定制选项对属性进行配置,这决定了存取方法的行为。下面的例子展示了一些简单的属性声明:

    @interface Person : NSObject {
        @public
            NSString *name;
        @private
            int age;
    }
    
    @property(copy) NSString *name;
    @property(readonly) int age;
    
    -(id)initWithAge:(int)age;
    @end

     属性的访问方法由@synthesize关键字来实现,它由属性的声明自动的产生一对访问方法。另外,也可以选择使用@dynamic关键字表明访问方法会由程序员手工提供。

    @implementation Person
    @synthesize name;
    @dynamic age;
    
    -(id)initWithAge:(int)initAge
    {
        age = initAge; // 注意:直接赋给成员变量,而非属性
        return self;
    }
    
    -(int)age
    {
        return 29; // 注意:并非返回真正的年龄
    }
    @end

    属性可以利用传统的消息表达式、点表达式或"valueForKey:"/"setValue:forKey:"方法对来访问。

    Person *aPerson = [[Person alloc] initWithAge: 53];
    aPerson.name = @"Steve"; // 注意:点表达式,等于[aPerson setName: @"Steve"];
    NSLog(@"Access by message (%@), dot notation(%@), property name(%@) and direct instance variable access (%@)",
          [aPerson name], aPerson.name, [aPerson valueForKey:@"name"], aPerson->name);

    为了利用点表达式来访问实例的属性,需要使用"self"关键字:

    -(void) introduceMyselfWithProperties:(BOOL)useGetter
    {
        NSLog(@"Hi, my name is %@.", (useGetter ? self.name : name)); // NOTE: getter vs. ivar access
    }

    类或协议的属性可以被动态的读取。

    int i;
    int propertyCount = 0;
    objc_property_t *propertyList = class_copyPropertyList([aPerson class], &propertyCount);
    
    for ( i=0; i < propertyCount; i++ ) {
        objc_property_t *thisProperty = propertyList + i;
        const char* propertyName = property_getName(*thisProperty);
        NSLog(@"Person has a property: '%s'", propertyName);
    }

    快速枚举

    比起利用NSEnumerator对象或在集合中依次枚举,Objective-C 2.0提供了快速枚举的语法。在Objective-C 2.0中,以下循环的功能是相等的,但性能特性不同。

    // 使用NSEnumerator
    NSEnumerator *enumerator = [thePeople objectEnumerator];
    Person *p;
    
    while ( (p = [enumerator nextObject]) != nil ) {
        NSLog(@"%@ is %i years old.", [p name], [p age]);
    }
    // 使用依次枚举
    for ( int i = 0; i < [thePeople count]; i++ ) {
        Person *p = [thePeople objectAtIndex:i];
        NSLog(@"%@ is %i years old.", [p name], [p age]);
    }
    // 使用快速枚举
    for (Person *p in thePeople) {
        NSLog(@"%@ is %i years old.", [p name], [p age]);
    }

    快速枚举可以比标准枚举产生更有效的代码,由于枚举所调用的方法被使用NSFastEnumeration协议提供的指针算术运算所代替了。

  • 相关阅读:
    fiddler 抓取 安卓模拟器 https包
    heidiSQL使用简介
    weblogic重启脚本
    svn命令在linux下的使用
    LVS之NAT和DR服务脚本
    LVS之NAT模型、DR模型配置和持久连接
    apache ab压力测试报错apr_socket_recv
    LVS负载均衡模型及算法概述
    Orcale11g单机安装与卸载
    IPC相关的命令
  • 原文地址:https://www.cnblogs.com/kingBook/p/6651716.html
Copyright © 2011-2022 走看看