当前在线人数8391
首页 - 分类讨论区 - 电脑网络 - 家有苹果版 - 同主题阅读文章

此篇文章共收到打赏
0

  • 10
  • 20
  • 50
  • 100
您目前伪币余额:0
未名交友
[更多]
[更多]
[Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
[版面:家有苹果][首篇作者:faucetQ] , 2009年02月02日21:35:31 ,1763次阅读,22次回复
来APP回复,赚取更多伪币 关注本站公众号:
[分页:1 ]
faucetQ
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 1 ]

发信人: faucetQ (fq), 信区: Apple
标  题: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Mon Feb  2 21:38:18 2009), 转信


整了个类似ObjectiveC学习笔记的东西,发上来大伙看看有兴趣不。
修改了一点,增加了NSAutoreleasePool的内容。
增加了NSString内容。

===========俺系分隔线==================

本文假设读者有基本的C编程能力,如果有C++或者Java的背景会更容易理解但是不是必须。

ObjectiveC基本语法

消息
在objectiveC中,向一个对象发送一个消息的语法为

[ obj method:parameter];

类似的功能在C++中写作

obj->method(parameter);

在java中写作
obj.method(parameter);

在smalltalk中写作
obj method:parameter

显而易见objectiveC和smalltalk的语法基本是相同的。

当有两个或者两个以上的参数时,通常试用以的语法
[ obj method:parameter1 WithSecondParameter:parameter2];

定义一个类的代码放在一个.h文件中,下面是一个例子。
//macdevexample1.h
@interface ClassName:SuperClassName{
//begin of instance variables
@private
int a;
@protected
float b;
@public
double c;
//end of instance variables
}
//begin of method declaration
- instanceExampleMethod1;//instance method with no parameter
+ classExampleMethod1;//class method

- exampleMethod2:(int)parameter1; //instance method with 1 parameter
- (int)exampleMethod3:(int)parameter1 WithSecondParameter:(double)parameter2;//instance method with 2 parameters

- (float)b;//method can have the same name of variable
- (void)setb:(float)_b;
//end of method declaration
@end
//end of macdevexample1.h

ObjectiveC类的定义以@interface开始,@end结束。@end后面不需要加分号,但是加了也不会有什么大问题。ObjectiveC中所有的类都以NSObject为基类(很久以前叫Object),这一点和Java类似。冒号表示继承关系。ObjectiveC不支持多重继承,但可以通过Protocal来实现和Java中Interface一样的类似多重继承的功能。数据部分包含在大括号中,缺省为protected。用@private,@protected,@public来规定access权限。ObjectiveC没有类变量(C++中的static型变量)。
ObjectiveC中的方法都为public。在声明方法时在方法命前加-表示是类的实例可以调用的方法, +表示是类对象可以调用的方法(类似于C++、java里面的static方法)。ObjectiveC定义类方法的语法同smalltalk类似,而不是像C++/Java一样同algo/C保持一致。对于从C++、java转过来的开发人员来说可能有些不习惯。

ObjectiveC方法若没有声明返回值则返回id类型数据,id实际上是一个指向所有类的指针,具体以后讨论。

实现一个类的代码会放在一个.m文件里
#import macdevexample1.h
@implementation ClassName
- instanceExampleMethod1{
//code goes here
}
+ classExampleMethod1{
//code goes here
}
...
@end
在objectiveC中可以试用#import或者#include来包含一个头文件。在使用#import时每个头文件只会被包含一次,避免了类和变量重复定义的问题。

创建一个类的实例通常使用如下代码
ClassA *objA = [[ClassA alloc] init];
或者
ClassA *objA = [ClassA new];
或者
id objA = [[ClassA alloc] init];

alloc为类方法,负责分配内存(在heap上),然后返回一个id。init是实例方法,负责初始化,然后返回一个id。同alloc类似的还有+ allocFromZone:(NXZone *)zone方法,zone会在以后讨论。init也会有带参数的initWithXXX之类的方法。new方法把分配内存和初始化在一个方法内完成。但土人俺觉得[[ClassA alloc] init]更清晰一点。除了某些ObjectiveC方言和使用特殊的trick之外,ObjectiveC的对象都分配在heap上。

当删除一个对象时,可以向该对象发送release消息 (这个类似于C++中的delete,但是release不真正删除实例)。

[objA release];

对于所有通过包含alloc,new或者copy的方法创建的对象需要自己发送release消息。

release消息并不保证对象会被从内存中清除。在ObjectiveC中,每个对象保存一个引用计数,当对象创建时,对象的引用计数为1,每次收到retain消息的时候引用计数会增加1,每次调用release的时候会减一。可以通过retainCount方法获得对象的retainCount。当对象的引用计数达到0的时候对象会向自己发送dealloc消息。dealloc方法负责把对象使用的内存清空,显而易见当创建自己的类的时候也要写一个自己的dealloc方法。可以说alloc和init相当于C++的constructor,dealloc相当于C++的destructor。


ObjectiveC还可以通过NSAutoreleasePool来管理内存。下面是一个如何NSAutoreleasePool的例子。

- testAutoreleasePool{
    int i;
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    //do something here...
    id a = [[[ Something alloc] init] autorelease];
   
    for( i = 0; i < 1000000; i ++ ){
        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
        //do something in the loop
        id b = [[[ SomethingHuge alloc] init] autorelease];
        //do something in the loop
        [loopPool release];
    }
    [pool release];
}
使用NSAutoreleasePool是一个很简单的事情,在每个方法开始的时候创建一个NSAutoreleasePool的实例,在方法中每创建一个临时对象就发送一个autorelease。最后在方法退出的时候向先前创建的NSAutoreleasePool的实例发送一个release消息,所有在这个方法中创建的临时对象都会被释放。在使用循环的时候最好也在每次循环开始的时候创建一个NSAutoreleasePool的实例,在循环结束的时候向先前创建的NSAutoreleasePool的实例发送一个release消息,所有在这个循环中创建的临时对象都会被释放。NSAutoreleasePool是俺这种懒人的大救星!在cocoa开发中,很多地方都依赖NSAutoreleasePool。在Cocoa的类库中有很多方法可以返回一个对象的实例但是方法的名字中不包含new, alloc或者Copy。这些方法返回的实例在返回之前都收到了一个autorelease消息。因此在使用这些方法的时候要在他们外面套上一层NSAutoreleasePool。

可以说ObjectiveC的内存管理介于C/C++和Java/Smalltalk之间。OS X 10.5可以使用自动内存管理,但是iphone不行,土人俺还在用10.4也没有这牛叉本事。

C++、java里面的this在objectiveC里面叫self(Smalltalk,Python, Objective Pascal,Ruby也叫self, VB里面叫Me,Perl里面用$_[0],PHP用$this表示实例用self表示类)。Java中的super在objectiveC中也叫super。

ObjectiveC中的BOOL类型的值为Yes和No而不是true和false。在ObjectiveC中, nil和Nil是不一样的。

Category是ObjectiveC提出的一个对类进行扩展的办法。C#3.0中extension methods的概念和ObjectiveC的Category类似。

一下是一个例子,我们首先定义一个mitbbsExampleLocation类,文件名为mitbbsExampleLocation.h。

#import <Cocoa/Cocoa.h>
@interface mitbbsExampleLocation : NSObject {
int x,y;
}
-(void)moveToX:(int)x andY:(int)y;
@end

下面是implementation。
#import "mitbbsExampleLocation.h"
@implementation mitbbsExampleLocation
-(void)moveToX:(int)x andY:(int)y{
    self->x = x;
    self->y = y;
}
@end

下面定义一个扩展mitbbsExampleLocation类的category,定义的方法就是在类的名字后面加一个小括号,然后把category的名字写在小括号里面,文件名不太重要,但是最好为DisplayData.h。
#import "mitbbsExampleLocation.h"

@interface mitbbsExampleLocation (DisplayData)
    -(void) displayLocation;
    -(void) displayX;
    -(void) displayY;
@end

下面是implementation

#import "DisplayData.h"
@implementation  mitbbsExampleLocation (DisplayData)
-(void) displayLocation{
printf("x=%d\ty=%d\n", self->x, self->y);
}
-(void) displayX{
NSAutoreleasePool * Pool = [[NSAutoreleasePool alloc] init];
NSLog([NSString stringWithFormat:@"%d\n", self->x]);
[Pool release];
}
-(void) displayY{
//................
}
@end

Protocol是ObjectiveC中实现多重继承的机制。ObjectiveC中有两种protocol,一种是非正式的,一种是正式的。非正式的protocol只是在文档中规定应该实现的方法。正式的Protocol和java中的interface类似。在protocol中开发人员可以定义方法但是不能定义实例变量。
@protocol mitbbsExampleClear
-(void) Clear;
@end

@interface betterLocation: mitbbsExampleLocation <mitbbsExampleClear>
-(void) Clear{
self->x = 0;
self->y = 0;
}
@end

ObjectiveC中的消息机制是其面向对象的核心。在objectiveC中,向一个对象发送一条消息的语法为

[receiver messageName:parameter];

这条命令会被编译器翻译为C代码

objc_msgSend(receiver, @selector(messageName), parameter);

在这里我们第一次遇到selector的概念。selector在objectiveC中的关键字为SEL。@selector(messageName)指令会返回一个同messageName相关的selector。

在GNUStep中, SEL的定义为如下C代码。
typedef const struct objc_selector
{
  void *sel_id;
  const char *sel_types;
} *SEL;

由此可见,selector实际上是一个由一个方法名的字符串和一个unique id组成的结构。所有同名的方法共有一个selector。当向某个对象发送消息时,objectiveC实际上告诉对象需要调用某个selector对应的方法,该对象会从自己的Class所保存的selector-method对应列表中查找是否可以相应该selector对应的方法,如果有就该干啥干啥,如果不存在该selector对应的方法,则在superClass里面查询,如果还是没有则调用message forward机制。message forward机制以后会讨论。

ObjectiveC会向实例方法传递两个隐含的参数,第一个为self第二个为该方法所对应的消息的selector。C++仅传递一个隐含参数this。同C相比增加的参数数量会影响性能,在IA32平台,参数通过栈传递,在PowerPC和x86-64平台参数通过寄存器传递。因此在PowerPC和x86-64平台增加的参数对性能的影响相对较小。

ObjectiveC的消息机制同C++相比更加灵活,但是相对效率较低。ObjectiveC本质上是动态的语言,而C++本质上是静态的语言,动态语言的本质导致ObjectiveC的效率必然比C++低。因此在使用ObjectiveC进行开发时,对性能要求比较高的部分最好不用使用消息机制(不要试用[receiver message]),而尽可能使用单纯的C语言。

在使用C代码时,可以试用@defs来获取ObjectiveC的Class的结构从而访问ObjectiveC中的private和protected变量。以上面的mitbbsExampleLocation为例。

首先我们定义一个struct

typedef struct {
@defs(mitbbsExampleLocation);
} *PLocation;

然后把一个指向mitbbsExampleLocation的指针cast成PLocation类型的变量。
PLocation p = (PLocation)[[mitbbsExampleLocation alloc]init];
然后我们就可以像使用一个C的struct一样使用mitbbsExampleLocation
p->x = 0;
p->y = 0;

需要注意的是@defs破坏了面向对象的原则因此是不被推荐使用的(好像这几年的文档上也看不到了,但是实际还是存在的)。

获取一个ObjectiveC类的方法可以使用以下方法。
以mitbbsExampleLocation类的moveToX:andY:为例,首先定义一个指向该函数的指针

void (*moveToXAndY)(id, SEL, int, int);

然后获取方法的地址

moveToXAndY = (void (*)(id, SEL, int, int))[aLocation methodForSelector:@selector(moveToX:andY:)];

然后moveToXAndY可以和调用普通方法一样调用但需要有连个隐含参数
moveToXAndY(anId, @selector(moveToX:andY:), 1, 2);

methodForSelector方法是在NSObject类中定义的。 其返回值为IMP。IMP的定义为

typedef id (*IMP)(id, SEL, ...);

所以IMP就是一个指向返回值为id的ObjectiveC方法。如果返回值为其他类型我们需要像上面一样自己定义一个方法的指针。

NSObject是目前所有ObjectiveC类的根类。NSObject中的NS表示NeXTSTEP。NSObject是在NSObject.h文件里定义的。其核心内容如下
@interface NSObject <NSObject> {
    Class isa;
}

+ (void)load;

+ (void)initialize;
- (id)init;

+ (id)new;
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
- (void)dealloc;

#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
- (void)finalize;
#endif

- (id)copy;
- (id)mutableCopy;

+ (id)copyWithZone:(NSZone *)zone;
+ (id)mutableCopyWithZone:(NSZone *)zone;

+ (Class)superclass;
+ (Class)class;
+ (void)poseAsClass:(Class)aClass;
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
+ (BOOL)conformsToProtocol:(Protocol *)protocol;
- (IMP)methodForSelector:(SEL)aSelector;
+ (IMP)instanceMethodForSelector:(SEL)aSelector;
+ (int)version;
+ (void)setVersion:(int)aVersion;
- (void)doesNotRecognizeSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector;

#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED
+ (BOOL)isSubclassOfClass:(Class)aClass;
#endif

+ (NSString *)description;

- (Class)classForCoder;
- (id)replacementObjectForCoder:(NSCoder *)aCoder;
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;

@end

先把所有的方法放在一边看数据。整个NSObject里面只有一个数据 Class isa。Class类型是在objc.h里面通过typedef定义的,原文为

typedef struct objc_class *Class;

所以Class就是一个指向objc_class结构的指针。而objc_class是在 objc-class.h里面定义的,内容为

struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;

struct objc_method_list **methodLists;

struct objc_cache *cache;
struct objc_protocol_list *protocols;
};

这里面最值的注意的是

const char *name;

这一行。objectiveC和C++不同,每个类的名字会被编译器存在编译后的代码中,这样可以在运行时确定类的名字,这是C++中没有的功能。

struct objc_ivar_list *ivars; 包含了instance variable的信息,例如名字,类型,位置,这样可以在运行时获得变量的相关信息。objc_ivar_list的定义为

struct objc_ivar_list {
int ivar_count;
#ifdef __alpha__
int space;
#endif
struct objc_ivar ivar_list[1]; /* variable length structure */
};

在objc_ivar_list的定义中,定义objc_ivar的代码为
struct objc_ivar {
char *ivar_name;
char *ivar_type;
int ivar_offset;
#ifdef __alpha__
int space;
#endif
};

struct objc_method_list **methodLists;这一行储存所有的方法的信息。当一个类或者一个实例收到一个消息的时候会在这个表里面查找有没有相对应的方法。同变量类似,ObjectiveC可以在运行时获取方法的名字等信息。

struct objc_method_list {
struct objc_method_list *obsolete;

int method_count;
#ifdef __alpha__
int space;
#endif
struct objc_method method_list[1]; /* variable length structure */
};


typedef struct objc_method *Method;

struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};

通过上面的分析,我们可以说isa指针(以及Class变量)和C++的vtable类似但是增加了很多其他信息,这些信息在二进制代码中也是可读的,使用class-dump(http://www.codethecode.com/projects/class-dump/)直接从objectiveC编译完成的二进制代码生成interface信息。

id也是在objc.h中定义的,代码为

typedef struct objc_object {
Class isa;
} *id;

所以本质上,id就是一个指向NSObject的实例的指针,由于在objectiveC中所有的类都是NSObject的子类,所以id可以用来指向任何类的实例。

在很久以前,ObjectiveC中的基类叫做Object,后来NeXTSTEP和Sun一起合作开发了一个叫做OpenStep的项目,所有的类前面都加上了NS。土人俺不知道这个NS到底是代表(N)eXT(S)TEP还是(N)eXTSTEP-(S)UN。OpenStep是后来的GNUStep和Cocoa的基础,因此现在的Cocoa中的类都带着NS。

现在我们已经提到了id,Class,SEL,IMP,BOOL, #import,@interface,@implementation,@protocol,@end,@private,@protected,@public,@selector(method_name), @defs(class_name)。下面一个重要的内容是NSString类。

在ObjectiveC中NSString和C字符串是共存的。
当定义一个NSString类的实例时可以使用下面的语法。

NSString *aNSString = @"Hello new world!";

@被用来区别C字符串和NSString。

使用initWithContentOfFile:encoding:error:方法,可以从文件直接创建一个NSString对象,使用writeToFile:atomically:encoding:error: 方法可以直接把NSString写入一个文件。例如下面的例子。

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSError *er = [[[NSError alloc] init] autorelease]; 
NSString *inPath = @"/Users/myusername/textin.txt";
NSString *outPath = @"/Users/myusername/textout.txt";

NSString *contentsOfFile = [[[NSString alloc] initWithContentsOfFile:inPath encoding: NSUnicodeStringEncoding error:&er] autorelease];
if( nil == contentsOfFile ){
NSLog( [er localizedDescription] );
}

BOOL result = [contentsOfFile writeToFile:outPath atomically:NO encoding: NSUnicodeStringEncoding error:&er];
if( NO == result ){
NSLog( [er localizedDescription] );
}
[pool release];

这个例子将textin.txt中的内容直接拷贝到textout.txt中。这个例子支持中文。

在ObjectiveC中直接创建中文NSString对象可以使用initWithUTF8String:(const char *)bytes方法,例如:

NSString *testA = [[NSString alloc] initWithUTF8String:"军版很牛叉!"];

NSString类提供了一系列将String变成数值的方法例如intValue,floatValue等等。
int a = [@"123" intValue];
而从数字和其他类型创建NSString可以使用initWithFormat方法。

NSString *stringWithFormat = [[NSString alloc] initWithFormat:@"int: %i, int: %d, unsigned int: %u, double: %f, char:%c, Object:%@",
1, 2, 3, 4.0f, 'h', @"lalala"];

NSSTring类提供了基本的compare,caseInsentitiveCompare, hasPrefix,hasSuffix等字符串比较查找功能。更复杂的功能可以使用NSPredicate(10.4以上)。

NSString的实例不能被修改,NSMutableString的实例可以修改。

NSArray是另外一个很重要的类。NSArray一旦创建就不能修改,需要修改的Array可以使用NSMutableArray。
创建一个Array可以使用以下代码。
NSArray *arrayObj = [[NSArray alloc] initWithObjects:
                    @"China", @"News", @"Board", @"Sucks", nil];

NSMutableArray *mutableArrayObj = [[NSMutableArray alloc] init];

[mutableArrayObj addObject: @"Military"];
[mutableArrayObj addObject: @"Board"];
[mutableArrayObj addObject: @"Rocks"];

在初始化一个NSArray的时候,可以使用initWithObjects方法,然后在后面放一串逗号分隔的对象,最后一个为nil表示结束。

在所有动态语言中Dictionary都是很重要的类,在ObjectiveC中提供了NSDictionary类。


ObjectiveC不支持namespace,土鳖俺认为这是很土的行为。



--
※ 修改:·faucetQ 於 Feb 10 15:29:35 2009 修改本文·[FROM: 129.2.]
※ 来源:·BBS 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 68.33.]

 
Forp
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 2 ]

发信人: Forp (mushrooms^turtle shells), 信区: Apple
标  题: Re: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Tue Apr 30 23:25:54 2013, 美东)

初学者看看这个video吧。

http://www.youtube.com/watch?v=UzIWWcCy3Os&playnext=1&list=PL54515103C712A53D&feature=results_main


--

※ 来源:·WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 107.]

 
Forp
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 3 ]

发信人: Forp (mushrooms^turtle shells), 信区: Apple
标  题: Re: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Tue Apr 30 23:26:25 2013, 美东)

初学者看看这个video吧。

http://www.youtube.com/watch?v=UzIWWcCy3Os&playnext=1&list=PL54515103C712A53D&feature=results_main


--

※ 来源:·WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 107.]

 
googlebot
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 4 ]

发信人: googlebot (bot), 信区: Apple
标  题: Re: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Wed May  1 16:21:13 2013, 美东)

objc 没什么, 但mac os的framework是极其庞大, 这个要花很多功夫,
--

※ 来源:·WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 24.]

 
iiiir
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 5 ]

发信人: iiiir (哎呀我最牛), 信区: Apple
标  题: Re: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Wed May  1 20:56:16 2013, 美东)

thanks for share. maybe you can upload the original txt or doc file for
better viewing?
--
还记得当初疯狂,却忘了你的模样

※ 来源:·WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 165.]

 
faucetQ
进入未名形象秀
我的博客
[回复] [回信给作者] [本篇全文] [本讨论区] [修改] [删除] [转寄] [转贴] [收藏] [举报] [ 6 ]

发信人: faucetQ (fq), 信区: Apple
标  题: Re: [Mac Dev]整了个ObjectiveC的笔记,看看气氛对得上不
发信站: BBS 未名空间站 (Thu May  2 09:17:02 2013, 美东)

我X, 这是啥时候的帖子了,咋被人翻出来了。原来的txt或者doc早就找不到了。
--
拿钱发帖毛掉光。


※ 来源:·WWW 未名空间站 海外: mitbbs.com 中国: mitbbs.cn·[FROM: 129.]

[分页:1 ]
[快速返回] [ 进入家有苹果讨论区] [返回顶部]
回复文章
标题:
内 容:

未名交友
将您的链接放在这儿

友情链接


 

Site Map - Contact Us - Terms and Conditions - Privacy Policy

版权所有,未名空间(mitbbs.com),since 1996