*XCode、Objective-C、Cocoa是什么?
XCode:IDE, 象eclipse, visual studio.
Objective-C:编程语言.
Cocoa:是一大堆函数库,就好像MFC、.NET、Swing这类玩意,人家已经写好了一堆现成的东西,你只要知道怎么用就可以了。
*Objective-C的一些语法的注意点
注意点一:我在程序中看到大量的加减号、中括号和NS****这种东西,他们是什么玩意儿?
1 加减号
+/-号表示一个函数、或者方法、或者消息的开始,怎么说都行。
+/-号是设置方法的scope。scope有class或 instance两种。instance methods以 -开头,class level methods以 +开头。带+号的方法类似于java的静态方法,不用创建实例都可以调用,例如Integer.parseInt就是java的一个静态方法,而"alloc"方法则是objective C中最常用的class level method,见下面的例子。带-号的方法则需要创建实例,通过实例来调用。
比如java中,一个方法的写法可能是:
private void hello(int ishello) {
//OOXX
}
用Objective-C写出来就是
-(void) hello:(int)ishello{
//OOXX
}
2 中括号
中括号可以认为是如何调用你刚才写的这个方法,通常在Objective-C里说“消息”。
比如java里你可以这么写:
this.hello(1);
在Objective-C里,就要写成:
[self hello:1];
3 NS****
Mac OS用的就是NextStep这一套函数库。函数库里面所有的类都用NextStep的缩写打头命名,也就是NS****了。比较常见的比如:
* NSLog
* NSString
* NSInteger
* NSURL
* NSImage
…
你会经常看到一些教学里面会用到:
NSLog (@”%d”,myInt);
这句话主要是在 console里面跟踪使用,你会在console里面看到myInt的值(在XCode里面运行的时候打开dbg窗口即可看到)。
NSLog相当于printf()
你还可以看到其他名字打头的一些类,比如CF、CA、CG、UI等等,比如
* CFStringTokenizer这是个分词的东东
* CALayer这表示Core Animation的层
* CGPoint这表示一个点
* UIImage这表示iPhone里面的图片
CF说的是Core Foundation,CA说的是Core Animation,CG说的是Core Graphics,UI说的是iPhone的User Interface……还有很多别的,等你自己去发掘了。
4. #import VS #include
记住永远都是使用#import。
2、@interface, @implement, .h file, .m file,以及class instance的调用
用objective c创建一个class,需要遵循下列规则:
1) 每个class都会有2个file: .h file (头文件,用于定义@interface) 和 .m file (用于定义@implementation,将实现@interface定义的method。
2) 变量是定义在@interface里,@implementation里不需要在声明
3) 方法是在@interface里声明,而方法的具体实现是写在在@implementation里
下面是一个最典型的class例子:
@interface
Fraction.h
#import <Foundation/NSObject.h>
@interface Fraction: NSObject {//NSObject类似于java的Object。继承以 class: parent 表示,就像这里的 Fraction: NSObject
//instance variables是定义在@interface Class: Parent { .... }中
int numerator;
int denominator;
}
//method是定义在@interface Class: Parent { .... }之后,@end之前
//沒有設定存取權限(protected, public, private)時,預設的存取權限為 protected
//方法定义的格式為:scope (returnType) methodName: (parameter1Type) parameter1Name;
//scope 有class 或 instance 兩種。instance methods 以 - 開頭,class level methods 以 + 開頭。scope的讲解见上面章节
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end //Interface 以一個 @end 作為結束
@implementation
Fraction.m
#import "Fraction.h"
#import <stdio.h>
@implementation Fraction //Implementation 以 @implementation ClassName開始,以 @end 結束。
//Implementation只需要实现interface里定义的方法,而不需要再声明变量
-(void) print {
printf( "%i/%i", numerator, denominator );
}
-(void) setNumerator: (int) n {
numerator = n;
}
-(void) setDenominator: (int) d {
denominator = d;
}
-(int) denominator {
return denominator;
}
-(int) numerator {
return numerator;
}
@end
如何调用上面创建的class
main.m
#import <stdio.h>
#import "Fraction.h"
int main( int argc, const char *argv[] ) {
//下面这行是最最最常用的创建object的代码。有几个注意点
//1. 所有创建的class instance都是指针变量,变量名前面要加"*"
//2. [Fraction alloc] 呼叫了 Fraction class 的 alloc method (it is a class level method,即该方法前的符号是"+")
//3. [object init] 是一個建構子(constructor)呼叫,負責初始化物件中的所有變數。它呼叫了 [Fraction alloc] 傳回的 instance 上的 init method
//4. 整行代码相当于java的 Fraction frac=new Fraction();
Fraction *frac = [[Fraction alloc] init];
//在 Objective-C中呼叫 methods 的方法是 [object method]
//调用单参数的方法的格式为[object method: param]
//调用多参数的方法的格式为[object method: param1 label1: param2 label2: param3 label3: param4]
[frac setNumerator: 1];
[frac setDenominator: 3];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
//Objective C一定要求你手动释放变量所占的内存。具体讲解见后面章节
[frac release];
return 0;
}
为了避免声明多个局部变量来保存临时结果, Objective-C允许你调用方法时嵌套信息。例:
[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];
带多个参数的方法
多个参数的方法的定义写法
(方法的数据类型)函数名: (参数1数据类型)参数1的数值的名字参数2的名字: (参数2数据类型)参数2值的名字 …. ;
举个例子,一个方法的定义:
-(void) setKids: (NSString *)myOldestKidName secondKid: (NSString *) mySecondOldestKidName;
实现这个函数的时候:
-(void) setKids: (NSString *)myOldestKidName secondKid: (NSString *) mySecondOldestKidName{
printf(myOldestKidName);
printf(mySecondOldestKidName);
}
调用的时候:
Kids *myKids = [[Kids alloc] init];
[myKids setKids: @”张大力” secondKid: @”张二力”];
相当于java中的:
public void setKids( string myOldestKidName, string mySecondOldestKidName){
…
}
Kids myKids = new Kids();
myKids.setKids (“张大力”, “张二力”);
声明属性
在@interface里,除了定义变量和声明方法,还可以声明属性。声明属性是实现getter & setter的方便形式. property声明要放在@interface的{ }括号之后 (跟方法的声明一样)
属性不会在你的类声明中创建一个新的实例变量。他们仅仅是定义方法访问已有的实例变量的速记方式而已,这也是getter & setter的作用。属性避免了为每个变量提供不同的getter和setter的需求。
简单例子:
@property int count;
等效于在头文件中声明2个方法:
- (int)count;
-(void)setCount:(int)newCount;
上述的声明是写在@interface里,而在@implementation里是使用@sycthesize来进行配对,因为上面的声明只是定义,并没有实现。例:在上面@interface (.h file)所对应的@implementation (.m file)里
@synthesize count;
等效于在实现文件(.m)中实现2个方法。
- (int)count{
return count;
}
-(void)setCount:(int)newCount{
count = newCount;
}
声明property的语法为:
@property (参数1,参数2)类型名字;
如:
@property(nonatomic,retain) UIWindow *window;
其中参数主要分为三类:
读写属性:(readwrite/readonly)
setter语意:(assign/retain/copy)
原子性:(atomicity/nonatomic)
各参数意义如下:
readwrite产生setter\getter方法
readonly只产生简单的getter,没有setter。
assign默认类型,setter方法直接赋值,而不进行retain操作
retainsetter方法对参数进行release旧值,再retain新值。
copysetter方法进行Copy操作,与retain一样
nonatomic禁止多线程,变量保护,提高性能
使用属性另外一个好处是:在代码中访问它们的时候,可以使用点语法。例如:
myObject.count = 100;
int count = myObject.count;
上面的代码等价于
[myObject setCount: 100];
int = [myObject count];
属性详解参考文档: http://flandycheng.blog.51cto.com/855176/556179
协议 (Protocol)
我觉得protocol就像java里的interface,而objective c的@interface则只是为你的class定义一个头文件.
如果你的class要实现某个protocol,那么就要实现该protocol的所有方法。
要声明你的class实现某个protocol,就要在@interface里将protocol name用"<>"包裹起来,但不需要你在@interface里声明protocol的方法。例:下面的例子采用了2个protocol
@interface MyClass : NSObject <UIApplicationDelegate, AnotherProtocol> {
...
}
...
@end
然后在对应的@implementation里实现protocol所声明的所有方法!
如果你要自定义一个custom protocol,则可以类似下面:
@protocol MyProtocol
- (void)myProtocolMethod;
@end
注意:protocol是不能够有父类,而且不能定义变量!
存储权限
Java 在 method和变量前加上 public/private/protected修飾語,而 Objective-C 的作法則只是對於变量 instance variable进行修饰。class的方法则没有存储权限,只有 +/-
預設的權限是 @protected
例:
Access.h
#import <Foundation/NSObject.h>
@interface Access: NSObject {
@public
int publicVar;
@private
int privateVar;
int privateVar2;
@protected
int protectedVar;
}
@end
Access.m
#import "Access.h"
@implementation Access
@end
main.m
#import "Access.h"
#import <stdio.h>
int main( int argc, const char *argv[] ) {
Access *a = [[Access alloc] init];
// works
a->publicVar = 5;
printf( "public var: %i\n", a->publicVar );
// doesn't compile
//a->privateVar = 10;
//printf( "private var: %i\n", a->privateVar );
[a release];
return 0;
}
Objective C的一些特别知识点
1、 id:
Objective-C有一种比较特殊的数据类型是id。你可以把它理解为“随便”。id类型我觉得类似于java的Object
在Objective-C里,一切东西都是指针形式保存,你获取到的就是这个对象在内存的位置。那么id就是你知道这个位置,但是不知道里面是啥的时候的写法。
Objective-C與 Java 跟 C++ 不一樣,你在呼叫一個物件的 method時,並不需要知道這個物件的型別。當然這個 method一定要存在,這稱為 Objective-C 的訊息傳遞。
2、同一个数组可以保存不同的对象:
比如一个数组NSArray,这种数组里面可以保存各种不同的对象,比如这个数组里:
myArray <—-|
0: (float) 234.33f
1: @”我是个好人”
2: (NSImage *) (俺的美图)
3: @”我真的是好人”
这是一个由4个东西组成的数组,这个数组包括一个浮点数,两个字符串和一个图片。
3、BOOL,YES,NO:
你可以认为YES表示C#或者Java里的true,NO表示false。而实际上YES是1,NO是0,但大于1则不为YES,BOOL本身就是个char。
Obejective-C中1不等于1,绝对不要将BOOL值和YES比较
4、IBOutlet、IBAction是啥玩意,总能看到。
这两个东西其实在语法中没有太大的作用。如果你希望在Interface Builder中能看到这个控件对象,那么在定义的时候前面加上IBOutlet,在IB里就能看到这个对象的outlet,如果你希望在Interface Builder里控制某个对象执行某些动作,就在方法前面加上(IBAction)。
5、nil。
相当于java的NULL。但nil是Object,可以发送消息给nil
如: [nil message]
6、为什么是@”字符串”而不是”字符串”
”字符串”是C的字符串,@””是一个NSString instance.
在需要NSString的地方才需要这个转化,例如NSLog里面.在需要C string的地方,还是用”字符串”的.
另外,@””这个转换是不支持中文的.例如NSLog(@”字符串”);是一定输出不了中文的.
7、指针变量的声明
可以是
NSString* str=@"hello";
也可以是
NSString *str=@"hello";
8. super & self
super相当于java的parent
self相当于java的 this
if ( self )跟 ( self != nil ) 一樣
9. class里的方法、变量、属性的获取方式的格式
调用方法的格式为: [object method]
获取变量的格式为: object->var
获取属性的格式为: object.property
例子:
MyClass.h
#import <Foundation/NSObject.h>
@interface MyClass: NSObject {
@public
int publicVar; //var
@private
int privateVar;
@protected
int count;
}
@property int count; //property
-(void) sayhello; //method
@end
MyClass.m
#import MyClass.h
@implementation MyClass
@synthesize count;
@property int count; //property
-(void) sayhello {
}
@end
- main.m
#import "MyClass.h"
#import <stdio.h>
int main( int argc, const char *argv[] ) {
MyClass *obj = [[MyClass alloc] init];
//call method
[obj sayhello];
//get var
obj->publicVar;
//access property
obj.count=100;
[obj release];
return 0;
}