objective-C面向对象理解(上)

时间:2022-05-09 19:48:25

在ObjC中定义一个类需要两个文件.h和.m:

  • .h文件:放类的声明,包括成员变量、属性和方法声明(事实上.h文件不参与编译过程);关键字@interface声明一个类,同时它必须以@end结束,在这两个关键字中间声明相关成员;在声明Person类的同时可以看到它继承于NSObject,这是ObjC的基类,所有的类最终都继承于这个类(但是需要注意ObjC中的基类或者根类并不只有一个,例如NSProxy也是ObjC的基类),由于这个类在Foundation框架中定义,所以导入了<Foundation/Foundaton.h>(这么描述的意思是导入Foundation框架中的Foundation.h声明文件);
  • .m文件:放属性、方法的具体实现;关键字@implementation用于实现某个类,同时必须以@end结尾,在这两个关键字中间实现具体的属性、方法;由于.m中使用了Person类,所以需要导入声明文件“Person.h”;
demo 在.h 文件中
#import <Foundation/Foundation.h>//由于使用了NSObject,所以导入此头文件

//NSObject是基类,Person实现了NSObject
@interface Person : NSObject{
/*成员变量必须包含在大括号中
*注意成员变量不声明任何关键字的话是默认可访问性@Protected
*注意在ObjC中不管是自定义的类还是系统类对象都必须是一个指针,例如下面的_name
*/
@private
NSString *_name;//在ObjC中推荐成员变量名以_开头
int _age;
@
protected
NSString *_nation;
@
public
float
height;
}

@end
  • @private 私有成员,只有当前类可以访问;
  • @protected 受保护成员,只有当前类或子类可以访问(如果没有添加任何修饰则默认为@protected);
  • @public 公共成员,所有类均可访问;
.m文件

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

int main(int argc, const char  * argv[]) {
@autoreleasepool {
Person *p=[[Person alloc] init];
//Person  p=[Person alloc];
// p=[p init];
//上面两句代码可以直接写成:Person *p=[[Person alloc] init];
//还可以写成:Person *p=[Person new];

p->height=1.72;
NSLog(@
"height=%.2f",p->height);//结果:height=1.72 %.2f是浮点型输出小数部分2位
}
return 0;
}
ObjC中所有的对象类型的变量都必须加上“*”,在ObjC中对象其实就是一个指针
  • ObjC中使用[]进行方法调用,在ObjC中方法调用的本质就是给这个对象或类发送一个消息;
  • 在ObjC中类的实例化需要两个步骤:分配内存、初始化;
  • 类的初始化调用了父类的init方法,如果使用默认初始化方法进行初始化(没有参数),内存分配和初始化可以简写成[Person new];
  • 公共成员的调用使用“->”操作符;
如果一个方法在.h中有声明则该方法是公共方法,如果没有在.h中声明直接在.m中定义则该方法是私有方法

方法的生命在h文件的end前面
//声明一个动态方法,没有返回值
-(void)setName:(NSString *)name;
//声明一个静态方法,没有返回值
+(void)showMessage:(NSString *)info;
在m中使用
//实现一个动态方法
-(void)setName:(NSString *)name{
_name=name;
}

//实现一个静态方法
+(void)showMessage:(NSString *)info{
NSLog(@
"%@",info);
}

通常一个成员的访问不会直接通过成员变量而是通过属性暴漏给外界
h文件  第一个括号是返回值类型,第二个是属性类型  
//声明age的setter、getter方法
-(int)age;
-(
void)setAge:(int)age;

m实现   调用属性的时候需要在属性名字前面加_划线  
//实现age的setter、getter方法
-(int)age{
return _age;//返回年龄
}
-(
void)setAge:(int)age{
_age=age;//设置年龄为age
}

这两个文件使用和声明都需要写出属性名称和冒号,在之前要加-符号,然后大括号里面写入做得事情

调用实例
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person alloc];
p=[p init];
//上面两句代码可以直接写成:Person *p=[[Person alloc] init];
//还可以写成:Person *p=[Person new];

//成员变量调用
p->height=1.72;
NSLog(@
"height=%.2f",p->height);//结果:height=1.72

//方法调用
[p setName:@"Kenshin"];//要加上@符号

//属性调用
p.age=28; //等价于:[p setAge:28];
int age=p.age;//等价于:age=[p age];
NSLog(@"age=%i",age); //结果:age=28

}
return 0;
}

ObjC中可以通过声明@property,同时通过@synthesize自动生成getter、setter方法(在新版本中甚至甚至都不用通过@synthesize只声明就可以使用)。我们通过一段代码来说明这个问题(为了方便大家查看代码,在下面的代码中暂时去掉前面定义的成员变量、属性等)

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject{
@
public
NSString *birthday;
NSString *_position;
NSString *_degress;
}

@
property NSString *birthday;

@
property NSString *position;

@
property NSString *degress;

@
property NSString *education;

@
property float weight;

-(
void)printInfo;
@end

Person.m文件
#import "Person.h"

@implementation Person

@synthesize birthday;
@synthesize position;
@synthesize degress=_degress;

@synthesize education;

-(
void)printInfo{
NSLog(@
"_weight=%.2f",_weight);
NSLog(@
"education=%@",education);
NSLog(@
"_degress=%@",_degress);
}
@end

main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

Person *p=[[Person alloc]init];
p->birthday=@
"1987-08-20"; // 复制的时候要加@符号,这时一个对象
p.birthday=@
"1986-08-08";
p->_position=@
"developer"; //调用公共属性
p.position=@
"architect";//调用自动生成的set方法

p.degress=@
"undergraduate";

p.education=@
"university";

p.weight=60.0;

NSLog(@
"p->birthday=%@,p.birthday=%@",p->birthday,p.birthday);
//结果:p->birthday=1986-08-08,p.birthday=1986-08-08

NSLog(@"p->_position=%@,p.position=%@",p->_position,p.position);
//结果:p->_position=developer,p.position=architect

NSLog(@"p.weight=%.2f",p.weight);
//结果:p.weight=60.00
[p printInfo];
/*结果:
_weight=60.00
education=university
_degress=undergraduate*/

return 0;
}
通过上面的代码我们可以看到最简单的方法就是直接通过@property就可以声明一个变量(例如weight属性),不需要进行实现即可直接使用;还可以使用@property声明再用@synthesize去实现(例如上面的birthday属性),不仅如此在实现的时候还可以指定实现此属性时使用哪个成员变量(例如degress属性)。

属性到成员变量,为什么[ p printInfo]是_weight? 如下:
  • 如果只声明一个属性a,不使用@synthesize实现:编译器会使用_a作为属性的成员变量(如果没有定义成员变量_a则会自动生成一个私有的成员变量_a;如果已经定义了成员变量_a则使用自定义的成员变量_a。注意:如果此时定义的成员变量不是_a而是a则此时会自动生成一个成员变量_a,它跟自定义成员变量a没有任何关系);
  • 如果声明了一个属性a,使用@synthesize a进行实现,但是实现过程中没有指定使用的成员变量(例如上面birthday):则此时编译器会使用a作为属性的成员变量(如果定义了成员变量a,则使用自定义成员变量;如果此时没有定义则会自动生成一个私有的成员变量a,注意如果此时定义的是_a则它跟生成的a成员变量没有任何关系);
  • 如果声明了一个属性a,使用@synthesize a=_a进行实现,这个过程已经指定了使用的成员变量:此时会使用指定的成员变量作为属性变量;

键字this用于表示当前对象,其实在ObjC中也有一个类似的关键字self,只是self不仅可以表示当前对象还可以表示类本身,也就是说它既可以用在静态方法中又可以用在动态方法中。


setName: andAge:方法是一个动态方法,此时self就代表调用对象;而在showMessage方法中self调用了类的静态方法printInfo,此时self代表调用的类;因此可以总结出在ObjC中self就代表当前方法的调用者。

参考自:http://www.cnblogs.com/kenshincui/p/3861302.html