Objective-C语法入门

    Objective-C是Mac软件开发领域最主要的开发语言。假如咱们对面向对象的思惟已经C语言都很熟悉的话,对于咱们学习Objective-C将会很是有用。假如咱们对C语言还不熟悉的话,那咱们须要学习一下C语言。 编程

    1. 方法调用(Calling Methods):
安全

    为了可以尽快上手,咱们先来看一些简单的例子。Objective-C语法里面基本的方法调用是这样的: 编程语言

[object method];
[object methodWithInput:input];
    对象的方法能够返回值:


output = [object methodWithOutput];
output = [object methodWithInputAndOutput:inpit];
     咱们也能够在类里面调用如何建立对象的方法。下面的这个例子里面,咱们调用了NSString类的string方法


id myObject = [NSString string];
     id的类型意味着myObject这个变量能够指向任意类型的变量。 当咱们编译这个应用程序的时候,并不知道他实现的真实的类和方法。在这个例子里面,很明显这个对象的类型应该是NSString,因此咱们能够改一下他的类型:


NSString * myString = [NSString string];
      如今myString就是一个NSString类型的变量。这个时候假如咱们试图使用一个NSString没有实现的方法时,编译器就会警告咱们。一定要注意在对象类型的右边有一个星号 全部的Objective-C对象变量都是指针类型的 id类型已经预先被定义成一个指针类型了。因此咱们不须要再加星号


    2. 嵌套消息调用(Nested Messages) 函数

    在许多编程语言里面嵌套消息,或者嵌套函数看起来就像这样:function1 ( function2() );function2的返回值被传递给function1当输入参数。 学习

    在Objective-C里面,嵌套消息调用就像这样:
this

[NSString stringWithFormat:[prefs format]];
    咱们应该尽可能避免在一行代码里面嵌套调用超过两个。由于这样的话,代码的可读性就不太好。


    3. 多参输入的方法(Multi-Input Methods)
atom

      多个输入参数的方法。在Objective-C里面,一个方法名能够被分割成几段。在头文件里面,就应该这样子来定义一个多输入参数的方法: spa


-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
      咱们这样来调用它:


BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO];
    参数不必定要给它命名。在运行期系统里面这个方法真实的名字叫writeToFile:atomically:。


    4. Accessors(Getter & Setter):
设计

    在Objective-C里面全部的实例对象默认都是私有的。全部在大多数状况下咱们须要用accessors去读取或者设置变量的值。有两个语法都支持这样的操做,这个是传统的老的语法: 指针

[photo setCaption:@"Day at the Beach"];
output = [photo caption];

     第二行的代码其实并不是直接去读对象实例的变量。事实上它调用的是名叫caption的方法。在Objective-C里大多数状况下咱们不须要给getters加get的前缀。不管何时咱们见到方括号,其实咱们都是向一个对象或者一个类发送了一个消息

    5. Dot Syntax

    在Objective-C 2.0里面,新增长了一个"."操做的语法。在Mac OS X 10.5里面就使用了Objective-C 2.0语法:

photo.caption = @"Day at the Beach";
output = photo.caption;
     咱们两种方式均可以使用。可是在一个工程里面最好保持风格一致,只使用某一种。"."操做只可以被使用在setters和getters里面,而不能用在通常意思的方法上。


    6. 建立对象

    主要有两种方式来建立一个对象。第一种办法像这面这样:

NSString* myString = [NSString string];
      这是一种很是习惯性的风格。在这种方式状况下,咱们建立的是系统自动释放(autoreleased)类型的对象。 关于自动释放类型autoreleased,咱们之后会深刻讨论一下。然而在许多状况下,咱们须要手动的去建立对象:


NSString* myString = [[NSString alloc] init];
    这是一个嵌套的方法调用。 第一个调用的NSString本身的alloc方法。这是一个相对比较底层的调用,由于他建立了内容,以及实例化了一个对象。第二块代码调用了新建立对象的init方法。 这个init方法实现了比较经常使用的基本设置,好比建立实例对象的参数。在一些状况下,咱们能够用不通的初始化方式去赋初值:


NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];
    7. 基本的内存管理


    假如咱们正在为Mac OS X开发一个应用程序,咱们能够选择是否启用垃圾回收机制。这就意味着咱们不须要去考虑内存管理,除了一个特别复杂的情形咱们须要处理一下。然而,咱们有的时候咱们的开发环境没有垃圾回收机制,好比iPhone开发的时候就没有垃圾回收机制。在这种状况下,咱们就须要了解一些基本的内存管理方面的概念。

    假如咱们手动的经过alloc建立了一个对象,咱们须要用完这个对象后release它。咱们不须要手动的去release一个autoreleased类型的对象,假如真的这样去作的话,咱们的应用程序将会crash。

// string1 will be released automatically
NSString* string1 = [NSString string];

// must release this when done
NSString* string2 = [[NSString alloc] init];
[string2 release];
     就这个教程而言,咱们能够人为autoreleased对象会在当前函数方法调用完成后被释放。 固然了,还有不少关于内存管理的只是咱们须要学习,可是这须要咱们了解更多的基本概念之后才能去涉及。


    8. 设计一个类的Interface

    就Objective-C语言而言,建立一个类很是简单。它很是典型的分红了两个部分。 类的接口一般保存在ClassName.h文件里,它定义了实例的参数,以及一些公开的方法。类的实现在ClassName.m文件里。它包含了真正运行的代码和那些方法。它还常常定义一些私有的方法。这些私有的方法对于子类是不可见的。

    这里有一个接口文件的大概。类名Photo,因此文件名叫Photo.h:

#import "Cocoa.h" @interface Photo:NSObject {
    NSString* caption;
    NSString* photographer;
}
@end
     首先,咱们把Cocoa.h import进来。Cocoa的应用程序的全部的基本的类大多都是这样作的。#import宏指令会自动的避免把同一个文件包含屡次。@interface符号代表这是Photo类的声明。冒号指定了父类。上面这个例子父类就是NSObject。在大括弧里面,有两个变量:caption和photographer。两个都是NSString类型的。固然了,他们也能够是任何别的类型包括id类型的。 最后@end结束整个声明。


    增长方法

   让咱们为成员变量加一些getters:

#import "Cocoa.h"
@interface Photo : NSObject {

    NSString* caption;
    NSString* photographer;
}

- caption;
- photographer;

@end
      别忘记,Objective-C方法不须要加get前缀。一个单独小横杆代表它是一个实例的方法。假如是一个加号的话,那就说明它是一个类的方法。编译器默认的方法的返回类型为id。还有全部的方法的参数的默认类型也都是id类型的。因此上面的代码从技术上讲是对的。可是不多这么用。咱们仍是给它加上返回类型吧:


#import "Cocoa.h"
@interface Photo : NSObject {

    NSString* caption;
    NSString* photographer;
}
- (NSString*) caption;
- (NSString*) photographer;
@end
     下面咱们再加上setters:


#import "Cocoa.h"
@interface Photo : NSObject {

   NSString* caption;
   NSString* photographer;
}
- (NSString*) caption;
- (NSString*) photographer;
- (void) setCaption: (NSString*)input;
- (void) setPhototgrapher:(NSString*)input;
@end
    类的实现    


    咱们经过实现getters来建立一个类的实现:

#import "Photo.h"
@implementation Photo
- (NSString*) caption {
   return caption;
}
- (NSString*) photographer {
   return photographer;
}
@end
    这部分的代码由@implementation再来加上类名开始,以@end结束。 就跟类的接口定义同样,全部的方法跟接口定义里的同样。 全部的对象都必要既要定义也要实现。 假如咱们之前也写过代码的话,Objective-C里面的getters看上去跟别的差很少。因此咱们下面就来介绍setters,它须要一点说明。


- (void) setCaption: (NSString*)input{
   [caption autorelease];
   caption = [input retain];
}
- (void) setPhotographer: (NSString*)input{
   [photographer autorelease];
   photographer = [input retain];
}
     每一个setter处理两个变量。第一个是当前存在对象的应用。第二个是新的输入对象。在支持垃圾回收的开发环境里,咱们只要直接赋新值就能够了:


- (void) setCaption: (NSString*)input {
   caption = input;
}
    可是假如咱们不能够用垃圾回收机制的话,咱们就须要先release旧的对象,而后retain新的对象。


   有两种方法能够释放一个引用对象:release 和 autorelease。标准的release会直接删除引用。autorelease方法会在未来的某个时候去release它。在它声明周期结束前,它会毫无疑问的存在。在本例中,上面setPhotographer中的photographer对象,将会在函数结束的时候被释放。 

    在setter里面用autorelease是安全的,由于新对象跟老的对象有多是同一个对象有可能指向的是同一个对象。对于一个咱们即将retain的对象,咱们不该该当即release它。这个也许如今看起来会困惑,可是随着咱们的学习,会愈来愈能理解它。如今咱们不须要马上彻底理解它。

    9. 初始化

    咱们能够建立一个初始化方法去给类的实例的成员变量赋初值:

- (id) init
{
   if ( self = [super init] )
   {
      [self setCaption:@"Default Caption"];
      [self setPhotographer:@"Default Photographer"];
   }
   return self;
}
      上面的代码感受没啥好解释的,虽然第二行代码好像看上去没啥用。这个是一个单等于号,就是把[super init]的值赋给了self。 它基本上是在调用父类去实现它的初始化。这个if代码段是设置默认值以前验证初始化是否成功。

    10. 释放资源Dealloc

    这个dealloc方法是在当一个对象但愿被从内容里面删除的时候调用。这个咱们释放在子类里面引用成员变量的最好的时机:

- (void) dealloc
{
   [caption release];
   [photographer release];
   [super dealloc]; 
}
      开始两行咱们发送了release通知给了两个成员变量。咱们不要在这里用autorelease。用标准的release更快一点最后一行的[super dealloc]很是重要。 咱们必需要发送消息去让父类清除它本身。假如不这么作的话,这个对象其实没有被清除干净,存在内存泄露。 dealloc在垃圾回收机制下不会被调用到。 取而代之的是,咱们须要实现finalize方法。

    11. More on Memory Management

    Objective-C的内存管理系统基于引用记数。全部咱们须要关心的就是跟踪咱们引用,以及在运行期内是否真的释放了内存。

    用最简单的术语来解释,当咱们alloc一个对象的时候,应该在某个时候retain了它。每次咱们调用了alloc或者retain以后,咱们都必需要调用release。这就是引用记数理论。可是在实践的时候,只有两种状况咱们须要建立一个对象:

        1. 成为一个类的成员变量

       2. 只临时的在一个函数里面被使用

    在更多的时候,一个成员变量的setter应该仅仅autorelease旧的对象,而后retain新的对象。咱们只须要在dealloc的时候调用release就能够了。因此真正须要作的就是管理函数内部的local的引用。惟一的原则就是:假如咱们alloc或者copy了一个对象,那么咱们在函数结束的时候须要release或者autorelease它。假如咱们是经过别的方式建立的,就无论。这里是管理成员对象的例子:

- (void) setTotalAmount: (NSNumber*)input
{
   [totalAmount autorelease];
   totalAmount = [input retain];
}
- (void) dealloc
{
   [totalAmount release];
   [super dealloc];
}
     这里是本地引用的例子。咱们只须要release咱们用alloc建立的对象:

NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
NSNumber* value2 = [NSNumber numberWithFloat:14.78];

// only release value1, not value2
[value1 release];
    12.  属性Properties

    前面咱们写caption和author的accessors的时候,你能够已经注意到了代码很是简明,应该能够被抽象提取出来。属性在Objective-C里是一个新的功能。他可让咱们自动的生成accessors,另外还有一些别的优势。咱们能够把上面Photo的类转成用属性来实现:

#import "Cocoa.h"
@interface Photo : NSObject {
   NSString* caption;
   NSString* photographer;
}
@property (retain) NSString* caption;
@property (retain) NSString* photographer;
@end
     @property是Objective-C来声明属性的编译指令。括号里面的"retain"指明了setter须要retain输入的对象。这行其余的部分指定了属性的类型以及名字。 下面让咱们来看看这个类的实现:

#import "Photo.h"
@implementation Photo
@synthesize caption;
@synthesize photographer;
- (void) dealloc
{
   [caption release];
   [photographer release];
   [super dealloc];
}
@end
      @synthesize指令自动的生成了咱们的setters和getters。因此咱们只须要实现类的dealloc方法。

    13. 调用nil对象的方法(Calling Methods on Nil)

    在Objective-C里,nil对象被设计来跟NULL空指针关联的。他们的区别就是nil是一个对象,而NULL只是一个值。并且咱们对于nil调用方法,不会产生crash或者抛出异常。这个技术被framework经过多种不一样的方式使用。最主要的就是咱们如今在调用方法以前根本无须去检查这个对象是不是nil。假如咱们调了nil对象的一个有返回值的方法,那么咱们会获得一个nil返回值。

    咱们能够经过nil对象让咱们的dealloc函数实现看上去更帅一点:

- (void) dealloc
{
   self.caption = nil;
   self.photographer = nil;
   [super dealloc];
}
      之因此能够这么作是由于咱们给把nil对象设给了一个成员变量,setter就会retain nil对象(固然了这个时候nil对象啥事情也不会作)而后release旧的对象。这个方式来释放对象其实更好,由于这样作的话,成员变量连指向随机数据的机会都没有,而经过别的方式,出现指向随机数据的情形机会不可避免。 注意到咱们调用的self.VAR这样的语法,这表示咱们正在用setter,并且不会引发任何内存问题。假如咱们直接去设值的话,就会有内存溢出:

    14. Categories

    Categories是Objective-C里面最经常使用到的功能之一。基本上category可让咱们给已经存在的类增长方法,而不须要增长一个子类。并且不须要知道它内部具体的实现。

    若是咱们想增长某个framework自带的类的方法,这很是有效。若是咱们想在咱们程序工程的NSString可以增长一个方法,咱们就可使用category。甚至都不须要本身实现一个NSString的子类。

    好比,咱们想在NSString里面增长一个方法来判断它是不是一个URL,那咱们就能够这么作:

#import "Cocoa.h"
@interface NSString (Utilities)
- (BOOL) isURL;
@end
     这跟类的定义很是相似。区别就是category没有父类, 并且在括号里面要有category的名字。名字能够随便取,可是习惯叫法会让人比较明白category里面有些什么功能的方法。这里是具体的实现。可是要注意,这自己并非一个判断URL很好的实现。咱们主要是为了总体的了解category的概念。

#import "NSString-Utilities.h"
@implementation NSString (Utilities)
- (BOOL) isURL
{
   if ( [self hasPrefix:@"http://"] )
   return YES;
   else
   return NO;
}
@end
     如今咱们能够在任何的NSString类对象里均可以调用这个方法了。下面的代码在console里面打印的"string1 is a URL":

NSString* string1 = @"http://www.CocoaDev.cn/";
NSString* string2 = @"Pixar";
if ( [string1 isURL] )
NSLog (@"string1 is a URL");
if ( [string2 isURL] )
NSLog (@"string2 is a URL");
      跟子类不同,category不能增长成员变量。咱们还能够用category来重写类原先的存在的方法,可是这须要很是很是当心。 记住,当咱们经过category来修改一个类的时候,它对应用程序里的这个类全部对象都起做用。

后记:上面Objective-C的比较基础的大概的讲了一下。Objective-C仍是比较好上手的。没有特别的语法须要去学习。并且一些概念在Objective-C里面被反复运用。

相关文章
相关标签/搜索