#import "Person.h"
#import "Student.h"
#import "Teacher.h"
#import "NewStudent.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
/*
OC中的方法
设置器与访问器
便利初始化函数 以及 便利构造器
属性
*/
//OC中的方法
//实例方法
//Person *a = [Person new];
Person *a = [[Person alloc] init];
//如何调用使用实例方法(通过对象调用)
[a sayHello];
[a sayHelloName:@"Yong" andAge:23];
//如何调用类方法(通过类名调用)
[Person sayHi];
[Person hiGuys];
//设置器与访问器
//我们知道,一个类的实例变量如果是被@protected或者@private 所修饰,那么我们将不能对该成员变量进行赋值.这满足了我们希望的封装和安全.但是为了交换信息,我们希望使用@pulice类型.似乎这两者的矛盾不可调节.这个时候我们就可以使用设置器与访问器来解决这个问题
Student *stu = [[Student alloc] init];
[stu setName:@"Yong"];
NSLog(@"%@",[stu name]);
[stu setAge:23];
NSLog(@"%ld",[stu age]);
//便利初始化函数 以及 便利构造器
Teacher *teacher = [[Teacher alloc] init];
[teacher sayWord];
Teacher *teacher1 = [[Teacher alloc] init];
[teacher1 sayWord];
Teacher *teacher2 = [[Teacher alloc] initWithName:@"Chen" andAge:23];
[teacher2 sayWord];
Teacher *teacher3 = [Teacher teacherWithName:@"ChenYong" andAge:24];
[teacher3 sayWord];
//属性
//在这里,我们可以使用点语法来访问属性,点语法被称为"语法糖果",它只是为了方便我们书写而发明的,它的本质还是getter和setter语法
NewStudent *newStudent = [[NewStudent alloc] init];
// [newStudent setName:<#(NSString *)#>]
newStudent.name = @"Yong";//(点语法赋值)
newStudent.age = 23;
newStudent.homeAddress = @"GZ";
NewStudent *newstudent = [[NewStudent alloc]initWithName:@"Yong" andAge:23 andHomeAddresss:@"GZ"];
}
return 0;
}
在Teacher.h文件里
#import <Foundation/Foundation.h>
@interface Teacher : NSObject
{
NSString *_name;
NSInteger _age;
}
-(void)sayWord;
//便利初始化函数(实例方法)
//注意命名规范:init开头
-(id)initWithName:(NSString *)name
andAge:(NSInteger)age;
/*
便利构造器(类方法)
便利构造器只不过是把对象分配内存 和 便利初始化函数 初始化对象的代码封装起来,让用户使用起来更加方便
注意命名规范: className 开头,例如teacher
*/
+(id)teacherWithName:(NSString *)name
andAge:(NSInteger)age;
@end
在Teacher.m文件里
@implementation Teacher
/*
id:返回的类型是id数据类型,它是动态数据类型,它可以指向任何的对象,而不关系具体类型,在运行时检查其具体类型,可以对其发送任何(存在的)消息
self:指向当前对象的指针
super:指向父类对象的指针,子类使用super发送消息时,实际上就是告诉子类调用我们父类的方法,如果父类没有定义该方法,则会继续在继承链上寻找,直到寻找到位置,如果找到NSObject位置依然没找到,就会报错
其中(self = [super init]),此处[super init]任然返回子类对象,此处的目的是为了初始化父类的实例变量,如果返回nil,表面父类没有alloc成功,即不能再alloc子类对象
*/
-(id)init //重写init
{
if (self = [super init])
{
_name = @"Yong";
_age = 23;
}
return self;
}
//便利初始化
-(id)initWithName:(NSString *)name
andAge:(NSInteger)age
{
if (self = [super init])
{
_name = name;
_age = age;
}
return self;
}
//便利构造器
+(id)teacherWithName:(NSString *)name
andAge:(NSInteger)age
{
Teacher *teacher = [[Teacher alloc] initWithName:name andAge:age];
return teacher;
}
-(void)sayWord
{
NSLog(@"Teacher who names %@,%ld years old,say hello guys",_name,_age);
}
@end
在NewStudent.h文件里
#import <Foundation/Foundation.h>
@interface NewStudent : NSObject
//{
// NSString *_homeAddress;
// NSString *_name;
// NSInteger _age;
//}
//对于homeAddress来说
//-(void)setHomeAddress:(NSString *)homeAddress;
//
//-(NSString *)homeAddress;
//属性的声明
//@property NSString *homeAddress; //相当于声明了设置器和访问器
//-(void)setHomeAddress:(NSString *)homeAddress;
//-(NSString *)homeAddress;
//完整的属性声明
/*
@property(readwrite,nonatomic,strong)NSString *homeAddress;
访问读写(readwrite),原子性(nonatomic),内存管理(strong)
访问读写:readwrite 指明属性是可读写的,这是默认值,因此可以省略.
readonly 指明属性是只读的,系统只会产生getter(访问器)方法,而不会产生setter(设置器)方法
可读写性确定属性是否有setter方法,他们是互斥的
对于只读写的属性,如果试图通过点语法给其赋值,会编译错误
原子性:atomic 原子性操作,这是默认的
nonatomic 非原子性操作,一般就使用它,但是它没有办法保证在多线程环境下不出错
内存管理:retain 会通过retain来持有目标对象,之前的对象会接收到释放的消息
copy 会通过copy复制对象,之前的对象会接收到释放的消息
assign 表面采用简单的赋值方式,这是默认的方式
strong 表示强引用关系,即拥有目标对象的所有权
weak 表示弱引用关系,不拥有目标对象的所有权,但目标对象被销毁,属性值会自动设置为nil
strong 相当于 retain 或者 copy,对象要用retain,copy,strong来描述
weak 相当于 assign ,基本数据类型要用assign 来描述
weak 与 assign 的区别
weak:可以描述对象
assign:不可以描述对象
*/
//@property 的设置器声明,这里没有下划线
//注意:直接操作实例变量而没有进行retain或copy操作,可能会引起内存泄露或者引用技术错误
@property(readwrite,nonatomic,strong)NSString *homeAddress;
@property(readwrite,nonatomic,strong)NSString *name;
@property(readwrite,nonatomic,assign)NSInteger age;
-(id)initWithName:(NSString *)name
andAge:(NSInteger)age
andHomeAddresss:(NSString *)homeAddress;
@end
在NewStudent.m文件里
@implementation NewStudent
//属性的实现(相当于设置器和访问器的实现),这句话也可以省略
//@synthesize homeAddress = _homeAddress;
/*
注意:如果我们把@synthesize注释掉了,这时候系统会为我们自动生成以下划线开头的变量.所以在类实现文件的内部,我们需要使用_name 来代替name,用_age 来代替age.
*/
//-(void)setHomeAddress:(NSString *)homeAddress
//{
// _homeAddress = homeAddress;
//}
//
//-(NSString *)homeAddress
//{
// return _homeAddress;
//}
-(id)initWithName:(NSString *)name
andAge:(NSInteger)age
andHomeAddresss:(NSString *)homeAddress
{
if (self = [super init])
{
// _name = name;
// _age = age;
// _homeAddress = homeAddress;
//对于只读readonly来讲,不能使用 self.age ,因为它没有设置器
//对于可读可写通常使用 self.name = name 的这种方式
self.name = name;
}
return self;
}
@end
在Student.h文件里
#import <Foundation/Foundation.h>
@interface Student : NSObject
{
NSString *_name;
NSString *_hobby;
NSInteger _age;
}
//设置器(setter)和访问器(getter)
//name的设置器
-(void)setName:(NSString *)name ;
-(void)setAge:(NSInteger)age;
//name的访问器
-(NSString *)name ;
-(NSInteger)age;
@end
在Student.m文件里
@implementation Student
//name的设置器
-(void)setName:(NSString *)name
{
_name = name;
}
//对于age属性来说,做正确性检验
-(void)setAge:(NSInteger)age
{
{
// _age = age;
if (age < 18)
{
_age = 18 ;
}
else
{
_age = age;
}
}
}
//name的访问器
-(NSString *)name
{
return _name;
}
-(NSInteger)age
{
return _age;
}
/*
设置器与访问器的作用
1.隐藏了实例变量
2.控制实例变量的读写
3.做正确性的校验
对于设置器与访问器来说,其命名规则:
1.设置器:-(void) set首字母大写的实例变量:(实例变量的返回值类型)去掉下划线的实例变量名
2.访问器:-(实例变量返回值类型) 去掉下划线的实例变量名
注意:
对于类的名称,其首字母要大写
对于变量,其首字母小写
遵循骆驼峰命名规则
有了setter 和 getter , 我们就可以把变量都定义@protected 或者 @private类型,尽量不要使用@public类型,它的好处如下:
1.在setter中加入合法性检查,例如判断年龄要大于0
2.更新被设置变量相关的其他变量的值,比如年龄与年份的关系
3.可以在debug中,在setter中追踪log
4.在多线程中,如果要保护对象的并发访问,侧必须在getter/setter中加入同步锁
缺点:手动编写麻烦
*/
@end
在Person.h文件里
@interface Person : NSObject
{
NSString *_name;
NSInteger _age;
NSString *_hobby;
}
/*
OC中的方法
方法:
是类的功能代码,在(.h)文件中声明,在(.m)文件中实现.
语法:
-|+ (返回类型) 方法名:参数列表
{
//方法体
}
减号(-)表示实例方法,加号(+)表示类方法
*/
-(void)sayHello;
//无返回值有参数实例方法
-(void)sayHelloName:(NSString *)name
andAge:(NSInteger)age;
//类方法
/*
注意:
1.类方法可以调用类方法
2.类方法不可以调用实例方法,但是类方法可以通过创建实例对象来访问实例方法
3.类方法不可以使用实例变量.类方法可以使用self,因为self不是实例变量
4.类方法作为消息,可以被发送到类里面去,不能发送到对象里面去
*/
+(void)sayHi;
+(void)hiGuys;
@end
在Person.m文件里
@implementation Person
//实例方法
-(void)sayHello
{
NSLog(@"sayHello!");
}
-(void)sayHelloName:(NSString *)name andAge:(NSInteger)age
{
NSLog(@"Hello guys!My name is %@,I am %ld years old!",name,age);
}
//类方法
+(void)sayHi
{
NSLog(@"sayHi!");
}
+(void)hiGuys
{
//1.类方法可以调用类方法
//self 是什么? self代表当前对象的指针
[self sayHi];
//2.类方法不可调用实例方法,但是类方法可以通过创建实例对象来访问实例方法
Person *p = [[Person alloc] init];
[p sayHello];
//3.类方法不可以使用实例变量.类方法可以使用self,因为self不是实例变量
// NSLog(@"hi,My is %@,age is %ld,hobby is %@",_name,_age,_hobby);
}
@end