OC学习第2天——CLASS

在新建文件时选择os x列表下的“source”,再从右面的选项中选择“cocoa class”,填写类名以及选择存储位置后会自动生成2个文件:一个.h文件和一个.m文件,格式如下

student.h:

#import <Foundation/Foundation.h>
@interface Student : NSObject
@end</pre>
student.m:
<pre class="lang:objc decode:true">#import "Student.h"
@implementation Student
@end

其中.h文件中定义类的属性、方法,和C++一样,OC中的属性也分为3种,private、protected、public。不过方法都是public的,而且不支持重载,比如:

#import <Foundation/Foundation.h>
@interface Student : NSObject{
@protected
    NSString * name;
    unsigned int age;
@public
    NSString * sid;
}
-(NSString *) getName;
-(void) setName:(NSString *) aName;
-(unsigned int) getAge; //无参数,冒号被省略
-(void) setAge:(unsigned int) aAge;
-(void) setNA:(NSString *)aName age:(unsigned int)aAge;
-(void) setNA:(NSString *)aName :(unsigned int)aAge; //同上 2个参数  age被省略 貌似变成了2个不同的函数
//-(int) getName; //oc不支持重载,所以即便返回值类型不同也不能重名
+(void) testfuc; // + 类方法
@end

和C++不同的地方就是声明一个类的语法不再是class而变成了@interface,上面这个student类继承自NSObject,这个基类和python中的object基类类似,提供了一些基本的构造函数、析构函数等来进行初始化以及回收操作。而且,oc中方法的声明和实现是写在两个文件中的,那个.m文件中写的就是方法的具体实现代码,下面再说。

类的继承以及属性的定义还比较容易理解,不过下面那些神码加号、减号、冒号的又是神码玩意??这种语法也太奇怪了吧?这里说说我个人的理解,如果有神码错误的地方,等以后学的更深入了再来改吧。

首先,+、-这两个符号定义了这个函数究竟是实例方法(-)还是类方法(+);

接着的括号中定义了函数的返回类型;

再接下来是函数名,这里是让我感到比较别扭的地方,比如

-(void) setNA:(NSString *)aName age:(unsigned int)aAge;

调用时候使用setNA这个函数名即可,不过后面的age也算是函数名的一部分,而这部分又可以被省略掉……上面说过OC中不支持函数的重载,即便参数类型和函数的返回值不同的情况下函数名一样也会报错。不过再声明一个函数比如:-(void) setNA:(NSString *)aName otherage:(unsigned int)aAge;

或者省略掉后面的参数名却是可以的,因为此时省略了后面函数名就代表着这是2个不同的函数了。

最后是一个“:(参数类型)参数名1 可省略的函数名:(参数类型)参数名2…”不考虑那个分家了的函数名的话这里也是比较好接受的。

所以,一个函数的声明整体来说结构如下:

+ or - 函数名:(参数类型)参数名1 可省略的函数名:(参数类型)参数名2….;

接下来进入.m去实现上面声明的函数,偷懒的办法就是把声明函数的代码复制过来,再把;替换成{}即可…

#import "Student.h"
@implementation Student
-(NSString *) getName{
    return name;
}
-(void) setName:(NSString *) aName{
    name = aName;
}
-(unsigned int) getAge{
    return age;
}
-(void) setAge:(unsigned int) aAge{
    age = aAge;
}
-(void) setNA:(NSString *)aName :(unsigned int)aAge{
    name = aName;
    age = aAge;
    NSLog(@"setna 1");
}
-(void) setNA:(NSString *)aName age:(unsigned int)aAge{
    name = aName;
    age = aAge;
    NSLog(@"setna 2");
}
+(void) testfuc{
    NSLog(@"is a class fuc");
}
@end

最后就是在主文件中引入我们写的类以及创建对象了,代码如下

#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
    Student * astduent = [[Student alloc] init]; //oc中内存都在堆上分配,所以要指针类型
    //Student *bstduent = [Stduent new];    //另一种方式创建
    astduent->sid = @"nsstring";// public属性直接访问
    [Student testfuc]; //类方法调用
    [astduent setName:@"abc"]; //实例方法掉用
    [astduent setNA:@"abc1" : 15];
    [astduent setNA:@"abc2" age:17];
    NSLog(@"student name is %@",[astduent getName]); //getName其实是一个返回NSString类型的函数
    NSLog(@"student age is %d",[astduent getAge]);
    }
    return 0;
}

至于@ [ ]的意思上文中已经说过了,至于alloc、init方法就是在基类中定义的,至于第二种方式引用一下别人的解释吧:

new方法是NSObject对象的一个静态方法,根据apple的文档,该方法实际上就是alloc和init方法的组合,实际上二者是一样的,但 apple还是推荐我们使用第一种方法,为什么呢?因为使用第一种方法,你可以使用自己定义的init方法来做一些初始化,当然,如果子类没有提供 init方法,自然调用的就是父类的init方法了。所以说,从安全性的角度来收,作为开发者我们在对象使用之前是一定要对对象进行初始化的,因此在定义类的时候一定要提供初始化方法。但是否一定要使用init作为方法名呢?答案是不一定。使用init作为方法名只是你重写了NSObject的init方法而已,如果你自己重新定义一个初始化方法,也是完全可以的,只要你在使用的时候记得调用新定义的初始化方法就可以了。

引用来源:http://www.oschina.net/question/54100_32468

最后看输出,也说明了上面的一点:

2015-02-11 21:52:43.506 helloword[1069:146145] is a class fuc
2015-02-11 21:52:43.507 helloword[1069:146145] setna 1
2015-02-11 21:52:43.507 helloword[1069:146145] setna 2
2015-02-11 21:52:43.507 helloword[1069:146145] student name is abcd
2015-02-11 21:52:43.507 helloword[1069:146145] student age is 17