Objective-C是Mac软件开发领域最基本的开发语言,假如我们对C语言已经非常熟悉或者具有面向对象语言的基础。对于我们学习Objective-C将会非常实用。





方法调用(Calling Methods)

为了可以尽快上手。我们先来看一些简单的样例。

Objective-C语法里面主要的方法调用是这种:





[object method];  

 

[object methodWithInput:input];  

 

对象的方法能够返回值:





output = [object methodWithOutput];  

 

output = [object methodWithInputAndOutput:input];  

 

我们也能够在类里面调用怎样创建对象的方法。以下的这个样例里面,我们调用了NSString类的string方法:





id myObject = [NSString string];  

 

id的类型意味着myObject这个变量能够指向随意类型的变量。

当我们编译这个应用程序的时候,并不知道他实现的真实的类和方法。





在这个样例里面,非常明显这个对象的类型应该是NSString。所以我们能够改一下他的类型:





NSString* myString = [NSString string];  

 

如今myString就是一个NSString类型的变量。这个时候假如我们试图使用一个NSString没有实现的方法时,编译器就会警告我们。





一定要注意在对象类型的右边有一个星号。

全部的Objective-C对象变量都是指针类型的。

id类型已经预先被定义成一个指针类型了。

所以我们不须要再加星号。

嵌套消息调用(Nested Messages)

在很多编程语言里面嵌套消息。或者嵌套函数看起来就像这样:





function1 ( function2() );  

function2的返回值被传递给function1当输入參数。在Objective-C里面。嵌套消息调用就像这样:





[NSString stringWithFormat:[prefs format]];  

我们应该尽量避免在一行代码里面嵌套调用超过两个。

由于这种话,代码的可读性就不太好。





多參输入的方法(Multi-Input Methods)

多个输入參数的方法。

在Objective-C里面,一个方法名能够被切割成几段。

在头文件中面,就应该这样子来定义一个多输入參数的方法:





-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;  

 

我们这样来调用它:





BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO];  

 

參数不一定要给它命名。在执行期系统里面这种方法真实的名字叫writeToFile:atomically:。





Accessors(Getter & Setter)  

 

在Objective-C里面全部的实例对象默认都是私有的。

全部在大多数情况下我们须要用accessors去读取或者设置变量的值。

有两个语法都支持这种操作,这个时传统的老的语法:





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

output = [photo caption];  

 

第二行的代码其实并不是直接去读对象实例的变量。

其实它调用的是名叫caption的方法。

在Objective-C里大多数情况下我们不须要给getters加get的前缀。

不管什么时候我们见到方括号,事实上我们都是向一个对象或者一个类发送了一个消息。





Dot Syntax

在Objective-C 2.0里面。新添加了一个"."操作的语法。在Mac OS X 10.5里面就使用了Objective-C 2.0语法:





photo.caption = @"Day at the Beach";  

output = photo.caption;  

 

我们两种方式都可以使用。可是在一个project里面最好保持风格一致。仅仅使用某一种。

"."操作仅仅可以被使用在setters和getters里面,而不能用在一般意思的方法上。





创建对象

主要有两种方式来创建一个对象。

第一种办法像这面这样:





NSString* myString = [NSString string];  

 

这是一种很习惯性的风格。在这样的方式情况下。我们创建的是系统自己主动释放(autoreleased)类型的对象。

关于自己主动释放类型autoreleased,我们以后会深入讨论一下。然而在很多情况下,我们须要手动的去创建对象:





NSString* myString = [[NSString alloc] init];  

 

这是一个嵌套的方法调用。第一个调用的NSString自己的alloc方法。这是一个相对照较底层的调用,由于他创建了内容,以及实例化了一个对象。





第二块代码调用了新创建对象的init方法。这个init方法实现了比較经常使用的基本设置,比方创建实例对象的參数。对于一般开发者而言,实现这个客户的类的详细的细节并不清楚。





在一些情况下,我们能够用不通的初始化方式去赋初值:





NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];  

 

主要的内存管理

假如我们正在为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对象会在当前函数方法调用完毕后被释放。





当然了,还有非常多关于内存管理的仅仅是我们须要学习。可是这须要我们了解很多其它的基本概念以后才干去涉及。

设计一个类的Interface

就Objective-C语言而言。创建一个类很easy。它很典型的分成了两个部分。





类的接口通常保存在ClassName.h文件中,它定义了实例的參数。以及一些公开的方法。





类的实如今ClassName.m文件中。它包括了真正执行的代码和那些方法。它还常常定义一些私有的方法。这些私有的方法对于子类是不可见的。





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





#import  

 

@interface Photo : NSObject {  

 

NSString* caption;  

 

NSString* photographer;  

 

}  

 

@end  

 

首先,我们把Cocoa.h import进来。Cocoa的应用程序的全部的主要的类大多都是这样做的。#import宏指令会自己主动的避免把同一个文件包括多次。





@interface符号表明这是Photo类的声明。冒号指定了父类。

上面这个样例父类就是NSObject。

在大括弧里面,有两个变量:caption和photographer。两个都是NSString类型的。

当然了,他们也能够是不论什么别的类型包含id类型的。

最后@end结束整个声明。

添加方法

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





#import  

 

@interface Photo : NSObject {  

 

NSString* caption;  

 

NSString* photographer;  

 

}  

 

- caption;  

 

- photographer;  

 

@end  

 

别忘记,Objective-C方法不须要加get前缀。一个单独小横杆表明它是一个实例的方法。假如是一个加号的话,那就说明它是一个类的方法。





编译器默认的方法的返回类型为id。还有全部的方法的參数的默认类型也都是id类型的。所以上面的代码从技术上讲是对的。可是非常少这么用。我们还是给它加上返回类型吧:





#import  

 

@interface Photo : NSObject {  

 

NSString* caption;  

 

NSString* photographer;  

 

}  

 

- (NSString*) caption;  

 

- (NSString*) photographer;  

 

@end  

 

以下我们再加上setters:





#import  

 

@interface Photo : NSObject {  

 

NSString* caption;  

 

NSString* photographer;  

 

}  

 

- (NSString*) caption;  

 

- (NSString*) photographer;  

 

- (void) setCaption: (NSString*)input;  

 

- (void) setPhotographer: (NSString*)input;  

 

@end  

 

Setters不须要返回不论什么值。所以我们把它的类型指定为void.





类的实现

我们通过实现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;  

 

}  

 

可是假如我们不能够用垃圾回收机制的话,我们就须要先retain旧的对象,然后retain新的对象。





有两种方法能够释放一个引用对象:release 和 autorelease。标准的release会直接删除引用。autorelease方法会在将来的某个时候去release它。

在它声明周期结束前。它会毫无疑问的存在。在本例中,上面setPhotographer中的photographer对象。将会在函数结束的时候被释放。





在setter里面用autorelease是安全的,由于新对象跟老的对象有可能是同一个对象有可能指向的是同一个对象。对于一个我们即将retain的对象。我们不应该马上release它。

这个或许如今看起来会困惑,可是随着我们的学习。会越来越能理解它。如今我们不须要立马全然理解它。





初始化

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





- (id) init  

 

{  

 

if ( self = [super init] )  

 

{  

 

[self setCaption:@"Default Caption"];  

 

[self setPhotographer:@"Default Photographer"];  

 

}  

 

return self;  

 

}  

 

上面的代码感觉没啥好解释的,尽管第二行代码好像看上去没啥用。

这个是一个单等于号,就是把[super init]的值赋给了self。

它基本上是在调用父类去实现它的初始化。这个if代码段是设置默认值之前验证初始化是否成功。





释放资源Dealloc

这个dealloc方法是在当一个对象希望被从内容里面删除的时候调用。

这个我们释放在子类里面引用成员变量的最好的时机:





- (void) dealloc  

 

{  

 

[caption release];  

 

[photographer release];  

 

[super dealloc];  

 

}  

 

開始两行我们发送了release通知给了两个成员变量。

我们不要在这里用autorelease。

用标准的release更快一点。





最后一行的[super dealloc];很重要。

我们必需要发送消息去让父类清除它自己。

假如不这么做的话,这个对象事实上没有被清除干净,存在内存泄露。





dealloc在垃圾回收机制下不会被调用到。

取而代之的是,我们须要实现finalize方法。

很多其它关于内存管理

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];  

 

这里是用本地引用对象去设一个成员变量的样例:





NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];  

 

[self setTotal:value1];  

 

NSNumber* value2 = [NSNumber numberWithFloat:14.78];  

 

[self setTotal:value2];  

 

[value1 release];  

 

注意到怎样管理本地引用事实上都是一样的。无论你是否把它设给了一个成员变量。

我们无须考虑setters的内部实现。





假设我们非常好的理解了这些的话,我们基本上理解了80%的Objective-C内存管理方面的内容了。

属性Properties

前面我们写caption和author的accessors的时候。你能够已经注意到了代码很简明,应该能够被抽象提取出来。





属性在Objective-C里是一个新的功能。他能够让我们自己主动的生成accessors,另外另一些别的长处。我们能够把上面Photo的类转成用属性来实现:





上面那个类原先的实现是这样:





#import  

 

@interface Photo : NSObject {  

 

NSString* caption;  

 

NSString* photographer;  

 

}  

 

- (NSString*) caption;  

 

- (NSString*) photographer;  

 

- (void) setCaption: (NSString*)input;  

 

- (void) setPhotographer: (NSString*)input;  

 

@end  

 

假如用属性来实现就是这样:





#import  

 

@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方法。





Accessors仅仅有当他们原先没有的时候,才会被生成。所以能够放心大胆的去用@synthesize来指定属性。并且能够任意实现你自己的getter和setter。编译器会自己去找哪个方法没有。





属性声明还有别的选项。可是限于篇幅层次,我们下次再介绍。

Logging





在Objective-C里。往console写日记很easy。其实NSLog()跟C语言的printf()两个函数差点儿全然同样。除了NSLog是用额外的“%@”去获得对象。





NSLog ( @"The current date and time is: %@", [NSDate date] );  

 

我们能够log一个对象到console里去。NSLog函数调用要输出对象的description方法。然后打印返回的NSString。我们能够在自己的类里重写description方法。这样我们就能够得到一个自己定义的字符串。

调用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,并且不会引起不论什么内存问题。

假如我们直接去设值的话,就会有内存溢出:





// incorrect. causes a memory leak.  

// use self.caption to go through setter  

caption = nil;  

 

Categories

Categories是Objective-C里面最经常使用到的功能之中的一个。 基本上category能够让我们给已经存在的类添加方法,而不须要添加一个子类。并且不须要知道它内部详细的实现。

假设我们想添加某个framework自带的类的方法,这很有效。假设我们想在我们程序project的NSString可以添加一个方法,我们就行使用category。甚至都不须要自己实现一个NSString的子类。

比方,我们想在NSString里面添加一个方法来推断它是否是一个URL。那我们就能够这么做:





#import  

 

@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里面被重复运用。

Objective-C基础语法高速入门的更多相关文章

  1. Shell 编程基础 --语法高速入门

    简单的说shell就是一个包括若干行Shell或者Linux命令的文件.对于一次编写,多次使用的大量命令,就能够使用单独的文件保存下来,以便日后使用.通常shell脚本以.sh为后缀.第一行一定要指明 ...

  2. Objective-C基础语法快速入门

    Objective-C基础语法快速入门 2010-11-04 16:32 折酷吧 zheku8 字号:T | T 假如我们对面向对象的思维已经C语言都很熟悉的话,对于我们学习Objective-C将会 ...

  3. Python3基础语法快速入门

    01 Python 简介 Python 是一种高层次的结合了解释性.编译性.互动性和面向对象的脚本语言.Python 由 Guido van Rossum 于 1989 年底在荷兰国家数学和计算机科学 ...

  4. Freemarker的基本语法及入门基础

    freemarker的基本语法及入门基础一.freemarker模板文件(*.ftl)的基本组成部分        1. 文本:直接输出的内容部分        2. 注释:不会输出的内容,格式为&l ...

  5. Java基础语法入门01

    Java基础语法入门01 学习java你要先进行去了解JDK,JRE,JVM JDK Java开发工具包 JRE Java语言开发的运行环境 JVM Java虚拟机,用于Java语言的跨平台所用. 当 ...

  6. JavaSE入门学习7:Java基础语法之语句(下)

    继续接着Java基础语法来:JavaSE入门学习5:Java基础语法(一)和JavaSE入门学习6:Java基础语法(二). 语句 Java经常使用的3种循环:while.do...while,for ...

  7. php从入门到放弃系列-02.php基础语法

    php从入门到放弃系列-02.php基础语法 一.学习语法,从hello world开始 PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器&qu ...

  8. Hadoop生态圈-Hive快速入门篇之HQL的基础语法

    Hadoop生态圈-Hive快速入门篇之HQL的基础语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客的重点是介绍Hive中常见的数据类型,DDL数据定义,DML数据操作 ...

  9. Python入门 —— 02基础语法

    基础语法入门学习推荐: 简明 Python 教程 下文仅为入门推荐书籍的补充与重点 多行语句:末尾使用斜杠 (  ) ,将一行分为多行 var = item1 + item2 + item3 注释: ...

随机推荐

  1. SQL基本查询_多表查询(实验三)

    SQL基本查询_多表查询(实验三) 题目要求(一) 针对emp.dept两表完成如下查询,并验证查询结果的正确性 使用显式内连接查询所有员工的信息,显示其编号.姓名.薪水.入职日期及部门名称: 使用隐 ...

  2. 浅析is和as两个关键词在类型转换时的使用

    is检查对象是否兼容与指定类型,返回Boolean值true或者false,值得注意的是,在使用is进行类型转换的时候是永远不会抛出异常的,例如: object o=new Object(); Boo ...

  3. kafka学习笔记1:测试环境搭建

    最近因为架构中引入了kafka,一些之前在代码中通过RPC调用强耦合但是适合异步处理的内容可以用kafka重构一下. 考虑从头学一下kafka了解其特性和使用场景. 环境选择 首先是测试环境的搭建,平 ...

  4. 虚拟机通信配置与Xshell连接

    本文主要讲解虚拟机通信配置的详细步骤和Xshell工具连接,以及如何诊断网络问题并进行相应配置的问题. 1. 虚拟机通信配置 虚拟机通信配置的基本流程如图所示: 首先,我们先打开新建的虚拟机,然后输入 ...

  5. 两个Xml转换为DataSet方法(C#)

    ///通过传入的特定XML字符串,通过 ReadXml函数读取到DataSet中.protected static DataSet GetDataSetByXml(string xmlData){   ...

  6. Java 面试题:百度前200页都在这里了

    基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...

  7. C++中类的多态与虚函数的使用

    C++的三大特性:封装.继承.多态.以前学的时候自己没去总结,记得在一本c++入门的书讲得还是比较清楚.今天上网找了一下多态,找到下面这篇文章写得比较清晰. http://pcedu.pconline ...

  8. ZooKeeper入门

    ZooKeeper简介 ZooKeeper是一个构建在Paxos算法上的高可用的分布式数据管理与系统协调框架,提供了一系列原语集,更上层的应用可以用它来实现同步,配置管理,名称服务,Master选举, ...

  9. java 之 简单工厂模式(大话设计模式)

    以前只是看设计模式,每次看完都去理解一次,并没有手动去写代码,所以理解的还不是很深刻,最近查看框架源码,发现很多地方用到的都是设计模式,因为对设计模式理解的不够深刻,所以源码查看进度很慢!现在决定来温 ...

  10. 【Java框架型项目从入门到装逼】第二节 - Spring框架 AOP的丧心病狂解说,你喜欢露娜的月下无限连吗?

    继续上一节的内容,多几个jar包: aop技术是面向切面编程思想,作为OOP的延续思想添加到企业开发中,用于弥补OOP开发过程中的缺陷而提出的编程思想.AOP底层也是面向对象:只不过面向的不是普通的O ...