Apple程序开发总结-- (二)Objective-C

来源:互联网 发布:多元非线性拟合算法 编辑:程序博客网 时间:2024/05/19 21:18

虽然Cocoa开发可以使用Objective-C、java和AppleScript,我只是用过Objective-C,后两种没尝试过。这里仅仅写点我对Objective-C的粗浅认识,这些东西很多是源于我C/C++的基础的,也许对java或.net等的程序员来说Objective-C 一开始接触比较难理解。

 

1 先写个“Hello,World!”程序吧。

 

#import <Foundation/Foundation.h> // 导入Foundation框架,与#include类似

 

int main(int argc, char *argv[]) {

 

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // NSAutoreleasePool 是Cocoa内存管理工具之一,只能回收一个线程内的不再使用的变量。当然,你也可以自己回收内存,不使用NSAutoreleasePool。

 

    NSLog(@"Hello World!"); // 同C的printf

 

    [pool release]; // 类似于COM的垃圾回收机制,不用了通过release方法告诉内存管理机制,该变量我不用了,但其他人用不用我就管不了。内存管理机制,有一套规则,变量申请、赋值给另一个变量等都要把计数器+1。不用了,通过调用release方法,其变量的计数器-1,减到0时就该回收该内存了。

 

    return 0;

}

 

 

2 类定义

通过一个自定义的类说明。

 

2.1 类声明

// Song.h 

#import <Foundation/NSObject.h> // 类似C的include,前面的Foundation与framework名相同,默认有几个是包含到工程中的,如用到没包含进来的framework,则需要在

 

@interface Song : NSObject{

 

@private // 当前类,其他可访问性标识符有@protected(当前类,子类),@public(所有类,包),@package(包)

id<ToolDelegate>  _delegate; // id是Objective-C的特殊类型,表示指针,与C++的void*类似

 

@public

NSString* _name;

 

NSString* _artist;        // NSString,字符串类,功能还是挺强大的;如果字符串要求可编辑建议用NSMutableString

 

int _NO;

 

}

 

@property (assign,nonatomic)id <ToolDelegate> delegate; // 属性声明,为实例变量指定属性(attributes)可让编译好器生成 无泄漏和线程安全的访问实例变量的方法.语法为:

 

@property (参数) 类型 名字;

这里的参数主要分为三类:
读写属性(readwrite/readonly)

                      readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用。


setter语意(assign/retain/copy):区别与用法有如下的一段解释:

 

With a retain property, your property setter claims ownership of the new value and relinquishes ownership of the old one. With an assign property, the surrounding code has to do this, which is just as mess in terms of responsibilities and separation of concerns. The reason you would use an assign property is in a case where you can't retain the value (such as non-object types like BOOL or NSRect) or when retaining it would cause unwanted side effects.

Incidentally, in the case of an NSString, the correct kind of property is usually copy. That way it can't change out from under you if somebody passes in an NSMutableString (which is valid — it is a kind of NSString).

 

简单说,给retain属性赋值时通过将新值的引用计数加1的方式获得其所有权,同时释放对旧值的所有权(通过引用计数减1);assign用于基本类型,如BOOL或NSRect等,或者你并不直接拥有的类型,比如delegates;copy用于一些特别的Object的,如NSString;


原子性atomicity(nonatomic,atomic

 

 

atomicity的默认值是atomic,读取函数为原子操作,多线程访问时不至于发生访问冲突。但如果不是多线程访问的话,声明为nonatomic,可以提高效率。


@property (assign,nonatomic)int _NO;            // 这里是基本类型,所以用了assign

@property (copy,nonatomic)NSString *_name; // NSString*类型用copy

@property (copy,nonatomic)NSString* _artist;

 

 

+(Song *) getSongInstance; // 类方法

 

- (id)initNewSong; // 实例方法

 

 

-(void) setValue:(int) NO name:(NSString*) songName artist:(NSString*) songArtist; // 方法定义,参数用":"隔开,name、artist等是lable,可以没有。

 

-(void) dealloc; // 类似于析构函数

 

@end // C++的类定义是以“;”结尾,Objetive-C是以"@end"结尾

 

 

2.2 类实现

// Song.mm

 

#import "Song.h"

 

@implementation Song

 

static Song *_instance = nil; // 这里想定义一个静态实例

 

@synthesize _delegate,_NO; // 与@property配合,实现中这样声明一下就可以让编译器自动生成读写函数,代替繁琐的setter, getter方法,

 

@synthesize _name;  // 访问方法SongObj._name 

@synthesize _artist;

 

 

 

+(Song *) getSongInstance{

 

@synchronized(_instance)

{

        if (_instance== nil)

{

            _instance = [[self alloc] init];

        }

}

 

    return _instance;

}

 

 

 

- (id)initNewSong{

if(!(self = [super init]))

{

return nil;

}

 

// Initialize members

_name = nil;

_artist = nil;

_delegate = nil;

_NO = 0;

 

return self;

}

 

 

-(void) dealloc{

 

if(_name)

[_name release];

 

 

if(_artist)

[_artist release];

 

 

// 这里的delegate不能调用release,因为其property是assign的。

 

[super dealloc];

 

}

 

 

// 方法调用 [Songobj setValue: NO name:@"歌名" artist:@"作者"]

-(void) setValue:(int) NO name:(NSString*) songName artist:(NSString*) songArtist{

_NO = NO;

_name = songName;

_artist = songArtist; 

}

 

 

@end

 

3 委托delegate以及事件处理

 

3.1 protocol

@protocol 定义一个协议,熟悉C++的话,可以把它理解成一个接口(interface)。

 

Objective-C只支持单继承,但可以实现多个协议(接口)。

 

 

定义一个Protocol,按照Cocoa的习惯,一般它以delegate结尾,熟悉C#的话应该知道它的意义。其实不论是接口,委托,还是回调函数,本质上都做了一件事情。就是定义了一个操作契约,然后由用户自己来实现它的具体内容。

 

@protocol MyUIViewDelegate

//这里只需要声明方法,不需要实现方法

@optional // 可实现可不实现的方法

- (int)anOptionalMethod:(int)arg;

 

@required

- (void)anotherRequiredMethod;

@end

 

实现多个协议的语法:

 

@interface Child : Parent <MyUIViewDelegate,MyDelegate2> {

//成员变量定义

}

//成员方法,类方法,属性定义

@end

 

在Child的实现中如下写:

@implementation Child

 

// Child的方法定义

 

 

// 实现的协议中的方法,其中@required方法必须实现

- (void)anotherRequiredMethod{

 

....

}

 

@end

 

3.2 cococa响应事件的机制


在Mac,Windows或者 Linux平台上,所有的GUI程序都可以称作消息驱动的,就是说整个应用程序就是在处理消息的循环中进行的,用户的操作或者系统发送的一些通知都会被送 到应用程序的消息处理循环中,比如用户通过键盘输入,用鼠标点击窗口等等,有些消息会直接派发给应用程序的对象,比如鼠标按下(MouseDown)的消 息就会直接被送给鼠标按下的那个窗口或者试图,但是有些消息会被系统首先解释,然后在生成其他的消息,比如用户用鼠标单击窗口Frame上的关闭按钮,这 个时候MouseDown事件并没有被送给应用程序的内部对象,而是在应用程序的消息循环中被解释成了窗口将要关闭的消息。(摘自网络)

 

还以上面自定义的MyUIViewDelegate为例,在UIViewControler中实现该delegate,并解释Cococa框架如何将UIView、UIViewControler、delegate三者其联系起来。

 

step1:

 

MyUIView的实现:

MyUIView定义了MyUIViewDelegate* delegate对象;

假设在MyUIView在发生某个事件后会调用doSometing方法。

 - (void)doSomething {

if( delegate != nil ) //这里的delegate就是UIView定义时的一个MyUIViewDelegate委托对象

{

[delegate func1]; //[]表示对一个对象发消息

}

}

 

step2:

 

让这个UIViewControler来实现上面定义的MyUIViewDelegate

@interface MyUIViewController : UIViewController <MyUIViewDelegate> {

//成员变量

UIView* view;

}

//成员方法,类方法,属性

 

@end

 

 

step3:

@implementation MyUIViewController

 

- (id)init {

MyUIView *myView = [[MyUIView alloc] init]; //对MyUIView进行初始化

myView.delegate = self; //将MyUIViewController自己的实例作为委托对象

self.view = myView;

}


- (void)anotherRequiredMethod {

//具体实现,可以加入Model相关的代码

}

 

 

@end

 

 

以上可总结为以下3步:

1.MyUIViewController初始化

2.MyUIViewController初始化时初始化MyUIView,并且将自己作为委托对象赋值给MyUIView

3.MyUIView发生事件,调用(回调)委托对象的方法,其实就是调用MyUIViewController的方法。

 

 

以上是通过自己定义一个控件(MyUIView)来解释如何定义委托,如何调用委托对象的方法,以及如何实现委托对象的方法。

 

如果使用Cococa框架的控件,则step1不需要实现,另外还需在Interface Builder中将控件的事件与事件处理函数绑定。

注意要将控件成员名称或property加上IBOutlet才能在Interface Builder中看到。