第一个例子:初识Objective-C
Hello World.m 文件
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here
NSLog(@"Hello, World!");
[pool drain];
return 0;
}
1. 在C/C++里面是#include,在java 里面是import,这里是#import
2. Foundation是cocoa提供给MAC OS的框架,提供给iphone的是其他的框架
3. NS 其实只是一个前缀,为了避免命名冲突
4. Autorelease是
内存管理的一种方式,不是立即把计数器减1,而是把这个过程放在
线程里面加以维护
5. Cocoa 把这个维护所有申请的内存的计数器的集合叫做pool
6. 通过告诉Objective-C 编译器[[NSAutoreleasePool alloc] init],编译器就会成功的编译生成NSAutoreleasePool对象
7. NSLog 相当于C 语言里面的printf
8. 字符串前面加上@符号,Objective-C 的编译器会认为这是一个NSString,NSString 封装了一系列的字符串的方法
第二个例子:类与对象
Cattle.h
#import <Foundation/Foundation.h>
@interface Cattle : NSObject {
int legsCount;
}
- (void)saySomething;
- (void)setLegsCount:(int) count;
@end
1. 在Objective-C 里面,类的定义从@interface 开始到@end 结束
2. NSObject 被称为root class,也就是根类
3. : NSObject表示继承自:NSObject
4. Objective-C 要求在括弧里面不能有方法的定义
5. 这个减号就是告诉编译器,减号后面的方法,是实体方法。实体方法的意思就是说,这个方法在类没有被实体化之前,是不能运行的。相应的,带加号的方法称为类方法,类方法可以脱离实体而运行。
6. 如果没有写返回值,则采用默认的返回值,类型是id
总结一下类的声明是这样的:
@interface 类的名字: 父类的名字{
实体变量类型实体变量名字;
}
- (返回值类型)方法名字;
+ (返回值类型)方法名字;
- (返回值类型)方法名字:(变量类型) 变量名字:(变量类型) 变量名字;
@end
Cattle.m
#import "Cattle.h"
@implementation Cattle
-(void) saySomething{
NSLog(@"Hello, I am a cattle, I have %d legs.", legsCount);
}
-(void) setLegsCount:(int) count{
legsCount = count;
}
@end
总结类的定义是这样的:
@implementation 类的名字
-(方法返回值) 方法名字{
方法定义
}
-(方法返回值) 方法名字:(变量类型) 变量名字{
方法定义
}
@end
Hello Class.m
#import <Foundation/Foundation.h>
#import "Cattle.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id cattle = [Cattle new];
[cattle setLegsCount:4];
[cattle saySomething];
[pool drain];
return 0;
}
1. 使用id 来代表一个对象。我们知道一个类仅仅是一些数据外加上操作这些数据的代码,所以id 实际上是指向数据结构的一个指针而已,相当于void*
2. Objective-C 使用消息(Message)来调用方法。所谓的消息就是一个类或者对象可以执行的动作。
格式为:[对象或者类名字方法名字:参数序列];
[Cattle new]就是说,向Cattle 类发送一个new 的消息。
3. 消息的优点:Objective-C 在编译的过程当中,编译器是会去检查方法是否有效的,如果无效会给你一个警告。但是编译器并不会阻止你执行,因为只有在执行的时候才会触发消息。
4. 消息的缺点:Objective-C 的这种方式要比直接从函数的入口地址执行的方式要消耗更多的执行时间。
第三个例子:继承
Bull.h
#import <Foundation/Foundation.h>
#import "Cattle.h"
@interface Bull : Cattle {
NSString *skinColor;
}
- (void)saySomething;
- (NSString*) getSkinColor;
- (void) setSkinColor:(NSString *) color;
@end
1. - (void)saySomething;是
重载了父类Cattle中的方法
总结一下继承的时候的子类的格式:
@interface 类的名字: 父类的名字{
实体变量类型实体变量名字;
}
- (返回值类型)重载的方法名字;
+ (返回值类型)重载的方法名字;
- (返回值类型)其他的方法名字:(变量类型) 变量名字:(变量类型) 变量名字;
@end
Bull.m
#import "Bull.h"
@implementation Bull
-(void) saySomething{
NSLog(@"Hello, I am a %@ bull, I have %d legs.",
[self getSkinColor],legsCount);
}
-(NSString*) getSkinColor{
return skinColor;
}-
(void) setSkinColor:(NSString *) color{
skinColor = color;
}
@end
1. %@表示字符串的占位符
2. self相当于是this,我们知道方法的调用格式是[对象或者类名字方法名字:参数序列];所以[self getSkinColor]表示本对象getSkinColor方法的返回值。父类对象用super表示
Hello Inheritance.m
#import <Foundation/Foundation.h>
#import "Cattle.h"
#import "Bull.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id cattle = [Cattle new];
[cattle setLegsCount:4];
[cattle saySomething];
id redBull = [Bull new];
[redBull setLegsCount:4];
[redBull setSkinColor:@"red"];
[redBull saySomething];
Bull *blackBull = [Bull new];
[blackBull setLegsCount:4];
[blackBull setSkinColor:@"black"];
[blackBull saySomething];
[pool drain];
return 0;
}
1. setLegsCount方法是Bull从父类Cattle中继承的
2. 从本质上来说,使用id 还是Bull *是没有任何区别的,但是建议写Bull *增加可读性