Objective-C 4 第一个类

习惯了java中的类只有一个文件,刚开始用OC不太习惯,用一段时间就好了。

一  简单语法

1  类

java中我们使用一个.java文件来描述一个类,但在OC中使用两个文件。

  1. .h文件:类的声明文件,用于声明变量、方法、属性。使用@interface和@end来声明。它只是一个声明文件,并不能写功能。
  2. .m文件:类的实现文件,用于实现.h文件中声明的方法,也可以实现其他方法。使用@implementation和@end声明。

2  方法

java中有动态方法(无static)和静态方法(staic修饰的)。OC中也有,它的区分比较个性。

+ 表示类方法,即静态方法,可以直接使用类名调用。

- 表示对象方法,即动态方法,只能使用对象调用。

声明方法和实现方法,都使用+或-开头。

.h文件中的方法权限是public的。

3  成员变量

成员变量的作用域有三种:

@public        全局都可以访问

@protected  只能在类内部和子类中访问

@private      只能在类内部访问


二 Xcode创建一个类

1 右击项目文件夹,选择“New File”。


2  选择OS X—— Source—— Cocoa Class。




3 输入类名,父类和使用的语言。


这里类名是Phone,父类是NSObject,Language有俩种:Objective-C和swift语言,这里我们使用Objective-C。

4 创建完毕后,项目中多了两个文件。


这两个文件名 和类名一致。
Phone.h文件是声明文件,Phone.m是实现文件。

三  第一个类代码解析

1. Phone.h——类的声明文件

#import <Foundation/Foundation.h>

@interface Phone : NSObject

@end
第一行导入了Foundation框架中的Foundation.h文件,NSObject被声明在Foundation.h中。
第三行表示OC中通过@interface声明一个类Phone,Phone类名后面跟 ":" 表示Phone继承自NSObject。后面还可以写<...>表示实现的接口,接口间以逗号分割。
第五行@end表示类的声明结束,@interface和@end是配套的。

2. Phone.m——类的实现文件

#import "Phone.h"

@implementation Phone

@end

第一行首先导入它的声明文件Phone.h,如果不导入这个肯定会有错的。。。。
第三行实现Phone类,@implementation后面表示实现的类名。
第五行@end表示类的实现结束,@implementaiton和@end是配套的。

四  设置成员变量

通常情况下,我们都把成员变量房子类的声明文件中,也就是头文件(.h文件)。

1  添加一个成员变量

#import <Foundation/Foundation.h>

@interface Phone : NSObject{
    int price;
}

@end
添加成员变量后我们发现多了一个{ }大括号。这是应该的,如果没有声明成员变量可以省略括号,如果有成员变量则需要写大括号,并且把成员变量写在括号中。
声明的变量price默认访问权限是protected,也就是可以在Phone类内部和子类中使用。

2  再添加几个不同作用域的变量

#import <Foundation/Foundation.h>

@interface Phone : NSObject{
    int price;
    @public
    float length;
    float weight;
    
    @protected
    int time;
    float version;
    
    @private
    float size;
}

@end

@public作用域的有:length weight

@protected作用域的有:price  time  version

@private作用域的有:size

五 添加方法

上面的的成员变量中有protected权限的,外界不能直接访问它。为了保证面向对象数据的封装性,我们可以提供price的get方法和set方法,让外界间接访问price。现在我们添加price的get和set方法。

#import <Foundation/Foundation.h>

@interface Phone : NSObject{
    int price;        //价格
    @public
    float length;     //长度
    float weitht;     //宽度
    
    @protected
    int time;         //上市时间
    float version;    //版本号
    
    @private
    float size;       //屏幕尺寸
}
//price的set方法
- (void)setPrice:(int)newPrice;
//price的get方法
- (int)price;

@end

第17行声明里price的get方法,方法名为price,OC建议get方法的名字跟成员变量保持一致(如果是在Java中,就应该叫做getPrice)。第17行最面的 - 表示这是一个动态方法( + 则表示静态方法)。price前面的(int)表示方法的返回值为int类型,方法的返回值参数类型都需要用小括号()包住。

第15行声明了price的set方法,前面的 - 表示动态方法,(void)表示方法没有返回值

在OC方法中,一个冒号:对应一个参数。由于第15行price的set方法接收一个int类型的参数,参数名为price,所以(int)newPrice前面有一个冒号:

 一定要记住:一个冒号:对应一个参数,而且冒号:也是方法名的一部分。因此第15行set方法的方法名是setPrice:,而不是setPrice

再加大一下难度,假如增加一个方法可以同时设置price和time,那么就应该这样写:

1 - (void)setPrice:(int)price andTime:(int)newTime;

* 这个方法是动态方法、没有返回值,接收2个参数,所以有2个冒号:

* 这个方法的方法名是setPrice:andTime:

* 其实andSize是可以省略的,它只是为了让方法名念起来通顺一点,也让(int)newTime前面的冒号:不那么孤单

2 实现方法


#import "Phone.h"

@implementation Phone

//price的get方法
- (int)price{
    return price;
}
//price的set方法
- (void)setPrice:(int)newPrice{
    price = newPrice;
}

- (void)setPrice:(int)newPrice andTime:(int)newTime{
    price = newPrice;
    time = newTime;
}
@end

上面实现了刚才点三个方法。

六  创建对象


接下来看一下使用这个类创建对象, 由于OC程序的入口点是main函数,所以在main.m文件中演示Phone类的使用。
#import <Foundation/Foundation.h>
#import "Phone.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Phone *ph = [[Phone alloc] init];
        
        [ph release];
    }
    return 0;
}

1  包含Phone.h

因为要用到Phone这个类,所以包含了它的头文件。
#import "Phone.h"

2 创建对象

在Java中是使用关键字new来创建对象,比如new Phone(),其实这句代码做了2件事:
  • 给对象分配存储空间
  • 调用Phone的构造方法进行初始化
在OC中创建对象也需要按顺序做上面所述的2件事

1)调用Phone类的静态方法alloc分配存储空间

Phone *ph = [Phone alloc];
  • OC是方法调用是用中括号[ ],方法调用者写在括号左侧,方法名写在括号右侧,中间留点空格。因此上面是调用了Phone类的静态方法alloc。
  • 上面调用的alloc方法会返回分配好内存的Phone对象,在等号左边用了一个指向Phone类型的指针变量ph来接收这个对象,注意stu左边的*号。所有OC对象都是用指针变量来接收的,如果你不了解指针,你记住下面这点就行了:利用类名定义一个变量时,类名后面一定要带个*号。
  • alloc方法是这样声明的:
+ (id)alloc;

可以看到,它的返回值类型是id,这个id代表任何指针类型,你可以暂时理解为:id可以代表任何OC对象,类似于NSObject *。

2)调用Phone对象的构造方法init进行初始化

前面调用alloc方法返回的Phone对象ph是不能正常使用的,因为仅仅是分配了内存,并没有进行初始化,接下来调用对象的init方法进行初始化

ph = [ph init];

看清楚了,由于init是动态方法,所以这里使用ph变量来调用,并不是使用类名来调用。init会返回已经初始化完毕的对象,再次赋值给了ph变量。这时候的Phone对象ph才能正常使用。

 

3)其实,我们最常见的做法是将alloc和init连起来使用:

Phone *ph = [[Phone alloc] init];

相信有面向对象开发经验的你一眼就能看懂了,在main.m完整代码的第7行。


3  销毁对象

由于OC不支持垃圾回收,因此当不再使用某个对象时,需要调用对象的release方法释放此对象。我们在第9行销毁了stu对象。

[ph release];

这个release方法在这里调用一次即可,不要觉得多调用多几次,对象就会释放地干净一点,这样做会很危险,容易造成野指针错误。

4 其他

1> 也可以调用静态方法new快速创建一个对象

1 Phone *ph = [Phone new];
2 
3 [ph release];

不过我们还是习惯使用alloc和init来创建对象

2> 前面我们调用了Phone的alloc、init、new方法,但是你会发现Phone.h中并没有声明这些方法,为什么能够调用呢?原因很简单,这些方法都是父类NSObject的,子类当然可以调用父类的方法。


七  访问公共成员和方法

#import <Foundation/Foundation.h>
#import "Phone.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Phone *ph = [[Phone alloc] init];
        
        // 访问公共变量length
        ph->length = 10.0f;
        
        // 调用setPrice:方法设置变量Price的值
        [ph setPrice:2700];
        
        // 调用setPrice:andTime:方法同时设置变量age和height的值
        [stu setPrice:1999 andTime:2014];
        
        // 访问公共变量length
        int length = ph->length
        // 调用price方法获取变量price的值
        int price = [ph price];
        
        // 打印no和price的值
        NSLog(@"length is %f and price is %i", length, price);
        
        [ph release];
    }
    return 0;
}

1.第7行创建了Phone对象,第26行销毁了对象

2.第10行和第19行访问了Phone对象的公共成员变量length,如果不是公共变量,不能像这样直接访问。注意访问方式:对象->成员变量

3.第13行调用了Phone对象的setPrice:方法,传入参数27修改了成员变量price的值

4.第16行调用了Phone对象的setPrice:andTime:方法,同时修改了成员变量price和time的值

5.第21行调用了Phone对象的price方法获取成员变量price的值

6.第24行输出了price和length的值,输出结果:

2015-12-05 21:54:56.221 Hello Object-C[1276:303] length is 10.000000 and price is 1999

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值