一、OC的点语法
在C++ 、JAVA、C#甚至是C中都能看到点语法,如下面一段C++代码:
//
// main.mm
// OC的点语法
//
// Created by 葬花桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#include <iostream>
using namespacestd;
class Car
{
public:
int speed;
Car();
~Car();
int getSpeed()
{
returnspeed;
}
};
Car::Car()
{
speed =0;
}
Car::~Car()
{
}
int main()
{
Car car;
car.speed =10;
cout <<"车速度为" << car.getSpeed() << "千米/时" << endl;
return0;
}
其中的car.getSpeed(); 和car.speed 就是用的点语法 ,一个是调用方法,一个访问数据成员。在OC中也有点语法,但是OC的点语法只能用在方法调用,不能访问成员变量。OC中对对象的操作只能通过指针进行,所以对成员变量操作只能用指针方式。
现在有这样一个OC类:
//
// Car.h
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Car : NSObject
{
int _speed;//速度
}
//speed的set和get方法
- (void)setSpeed:(int)speed;
- (int)speed;
@end
//
// Car.m
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import "Car.h"
@implementation Car
//speed的set和get方法
- (void)setSpeed:(int)speed
{
_speed = speed;
}
- (int)speed
{
return_speed;
}
@end
在使用这个类是时小桥在类的使用笔记中说过,是在中括号中完成的。比如:
//
// Car.m
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import "Car.h"
@implementation Car
//speed的set和get方法
- (void)setSpeed:(int)speed
{
_speed = speed;
}
- (int)speed
{
return_speed;
}
@end
现在小桥用点语法重写这个main函数如下:
//
// Car.m
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import "Car.h"
@implementation Car
//speed的set和get方法
- (void)setSpeed:(int)speed
{
_speed = speed;
}
- (int)speed
{
return_speed;
}
@end
这里的 car.speed = 10;就是OC的点语法了,它和 [car setSpeed:10];这一句是等价的,注意:它不是访问成员变量speed,而且类中也没有speed成员变量!在编译时,编译器会把它替换成 [car setSpeed:10];所以本质上它依然方法调用,而且只能是方法调用。再看,NSLog中的 car.speed这一句是调用_speed的get方法,二者的区别是一个有赋值,一个没有赋值!对于初学者比如小桥我来说,还是用中括号吧,免得搞混了。下面来张调试图片
二、@property和@synthesize
@property关键字是写在类的声明中,用来代替set和get方法的声明。你可能猜到了,@synthesize关键字是写在类的实现中,用来代替set和get方法的实现。那么,上面的Car类就可以这样写:
//
// Car.h
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Car : NSObject
{
int _speed;//速度
}
//speed的set和get方法
//- (void)setSpeed:(int)speed;
//- (int)speed;
@property int speed;
@end
//
// Car.m
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import "Car.h"
@implementation Car
//speed的set和get方法
//- (void)setSpeed:(int)speed
//{
// _speed = speed;
//}
//- (int)speed
//{
// return _speed;
//}
@synthesize speed =_speed;
@end
Run一下,输出10,完全没问题。和点语法一样,当编译器读到这两个关键字的时候也会把他们替换成小桥注释掉的代码,所以OC类中成员变量加下划线开头在这里就有作用。这样,十几行的代码就减少到了两行,这够简洁了吧?还不是,还可以更简洁。
小桥把实现中的@synthesize这行代码注释掉,Run一下, 如下图:
还是正常输出,这是因为在Xcode的高级版本中,@property已经不仅仅是声明set和get方法了,它连@synthesize的功能也有了,小桥的Xcode版本为4.6.3,不是最新的。这样,代码又减少了一行,已经最简洁了吗?还没有,还可以更简洁,可以在类中不声明成员变量。如下面代码:
//
// Car.h
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Car : NSObject
//{
// //int _speed; // 速度
//}
//speed的set和get方法
//- (void)setSpeed:(int)speed;
//- (int)speed;
@property int speed;
@end
id是OC中的一个万能指针,为什么说万能呢,因为它可以指向OC中的任何对象。可以把它看成是 NSObject * 类型,实际上在OC中的定义也类似。前面说过,NSObjectOC中的一个根类,要实例化对象绝大部分类都要继承它,又因为多态性,使得父类的指针可以指向子类,于是id指针就可以指向任何一个类了。
四、构造方法
OC的构造方法小桥上面也用到了,Car *car = [[Car alloc] init]; 以前用的是[Car new]来实例对象,new是类方法,它与 [[Car alloc] init];是一样的,alooc是也是类方法,在内存中创建一个对象,init是对象方法,它初始化这个对象,当我们没有重写构造方法的时候,调用的是NSObject类中的init方法,所以初始化后成员变量全部为0。现在重写init方法就是使得初始化后成员变量的值为我们想要的值。
重写的话就要在子类的实现中去重新写实现的代码,代码如下:
//
// Car.h
// 第一个OC程序
//
// Created by 葬花 桥 on 14-5-5.
// Copyright (c) 2014年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Car : NSObject
//{
// //int _speed; // 速度
//}
//speed的set和get方法
//- (void)setSpeed:(int)speed;
//- (int)speed;
@property int speed;
@end
读者可能看到重写的init方法是一个对象方法,而且它的返回值是id类型,前面说过id是一个万能指针,可以指向任何OC对象,因为每一个类要实例化对象都要有构造方法,而每个类都不同,所以这里返回类型为id类型。再看 self = [super init]
这一句代码,self是方法调用者本身,这里是对象,super是父类指针,子类中必须调用父类的构造方法,因为必须要为父类中声明的成员变量进行初始化,然后再初始化子类中的成员变量。最后返回self
最后测试一下:
可以看到,小桥没有调用speed的set方法,但是输出的速度为100,这就是初始速度!