一、 点语法
知识点
1.用点语法替换set和get方法
1)获取年龄:[p age];设置:[p setAge:10];
2)用点语法替代1):p.age=10;
3)原理:不是访问成员变量 ,访问成员变量用->;当编译器遇到点语法时,会自动展开为1)的形式[p setAge:10];
即点语法的本质是:方法调用;
4)int a=p.age;//等价于get方法;赋值时转化set;取值时转化get;
2.验证是调用了set和get方法:
1)在set和get放来句打印
2)设置断点,进入方法:点击 “下箭头的” 进入
3).出现动态变量的值:点击分栏效果
3.点语法的注意点
1)在set方法里:self.age=age;
//后果:[self setAge:age];
//死循环,点击stop停止,点击clear 清除
2)在get方法里:self.age;
//后果:[self age];
//死循环,点击stop停止,点击clear 清除
3)点语法就是set和get方法;没有相应的set和get方法 不能用 会报错
代码举例
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _age;
NSString *_name;
}
- (void)setAge:(int)age;
- (int)age;
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
//Person.m
#import "Person.h"
@implementation Person
- (void)setAge:(int)age
{
//_age = age;
NSLog(@"setAge:");
// 会引发死循环
//self.age = age; // [self setAge:age];
}
- (int)age
{
NSLog(@"age");
return _age;
// 会引发死循环
//return self.age;// [self age];
}
- (void)setName:(NSString *)name
{
_name = name;
}
- (NSString *)name
{
return _name;
}
@end
//main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{
Person *p = [Person new];
// 点语法的本质还是方法调用
p.age = 10; // [p setAge:10];
int a = p.age; // [p age];
p.name = @"Jack";
NSString *s = p.name;
NSLog(@"%@", s);
return 0;
}
二、 成员变量
知识点
1.作用域就是在什么范围能直接访问成员变量:*在(类的实现里)对象方法里可以直接访问(直接就是通过变量名访问)
2.成员变量的作用域 4种
1)@private //只能在当前类的对象方法里可以直接访问 所以main里不可以访问;
子类方法里也不能,但是子类内存里还是有这个成员变量的 (instance:实例)
但是想访问这个变量呢?:通过父类的set和get方法访问
2)@protected//能在当前类和子类的对象方法里可以直接访问 所以main里不可以访问 (instance:实例)默认的
3)@public//意味着在任何地方都可以访问 比如实现文件里; main里
4)@pakeage//介于私有和公共的,如果我的类和你的类处于一个框架里,我可以直接访问你的成员变量
3.一次写 作用于 下面所有
4.实现里 也可以写成员变量(但是不能和声明里的重名) 但是默认是私有的。
因为没人会包含.m文件,就也不会用到,所以其他作用域符没意义了;但是成员变量外面要有{};
5.在main之前,可以直接写类的实现继承NSObject ;里面写成员变量和相关方法 (就是说类的声明可以不写,但是不建议这样)
这时其他作用域符起作用的
6.只要看得见,才能拿来用。否则,不行
7.继承:也会把类实现里成员变量继承过来,属于单继承(避免多继承中不同类出现相同的东西,不好区分)
8.父类==超类:superclass ;子类:subclass/subclasses
代码举例
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _no;
@public // 在任何地方都能直接访问对象的成员变量
int _age;
@private // 只能在当前类的对象方法中直接访问
int _height;
@protected // 能在当前类和子类的对象方法中直接访问
int _weight;
int _money;
}
- (void)setHeight:(int)height;
- (int)height;
- (void)test;
@end
三、 @property和@synthesize
知识点
1.自动生成setter和getter方法声明:
@propert int age;//编译器特性,遇到自动展开set和get方法声明 格式: @property 类型 名字;
2.自动生成setter和getter方法实现:
@synthesize age=_age;//编译器特性,遇到自动展开set和get方法实现
格式: @synthesize 名字1=成员变量1[, 名字2=成员变量2];
(名字要和@property的一样)可以连着写
3.P:property C:class
4.最简单的写法:
1)同类型的写在一起
2)@synthesize 名字1=成员变量1;不写成员变量1,会自动生成@private的成员变量1,子类不能访问
3)成员变量和setter和getter方法一起搞定:@property int age;
5.细节
1)用越少的代码去实现更强大的功能。
2)@synthesize 名字1;//代表会访问和"名字1"一样的成员变量 ,不存在就会自动生成"名字1"的成员变量
3)@property只能写在interface里 @synthesize只能写在@implementation里
4)生成原则:没有帮你生成,有,则不生成任何东西,不存在的成员变量也不会生成
代码举例
//.h里的@property
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _age;
// int age;
int _height;
double _weight;
NSString *_name;
}
// @property:可以自动生成某个成员变量的setter和getter声明
@property int age;
//- (void)setAge:(int)age;自己写
//- (int)age;
@property int height;
//- (void)setHeight:(int)height; 自己写
//- (int)height;
- (void)test;
@property double weight;//利用@property参数
@property NSString *name;
@end
//.m里的@synthesize
#import "Person.h"
@implementation Person
// @synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量
@synthesize age = _age;
@synthesize height = _height;
@synthesize weight = _weight, name = _name;
@end
四、 id类型
知识点
1.可以定义变量,变量名不能写成id
2.id是万能指针,能指向/操纵任何OC对象
3.不用写* 星号
4.头文件里 @property int age;
5.id d=[Person new];//万能
6.NSObject *o=[Person new];//多态
7.id相当于 NSObject * (所有OC)类 *
8.void test(id d);//任何对象都能传进来
9.@perproty id d;//头文件里
五、 构造方法
知识点1:构造方法基本概念
1.一般情况下 创建对象 [Person new];
2.完整的创建一个可用的对象 1)分配存储空间 +alloc 2)初始化 - init
3.new 方法 内部分别调用两个方法 实现1)2)
4.按住 option 点击方法 进入方法;或者双击方法名 看右边 波浪线的图标
5.(2.1)Person * p1=[Person alloc];//分配空间并返回一个Person类型的新对象
(2.2)p1=[p1 init];//返回一个初始化好的对象
6.用new 只能用init进行初始化,所以分开使用,可以选择自己的方法去初始化
7.Person *p3=[[Person alloc] init];//可以这样写,建议这样写
8.init就是构造方法,用来初始化对象的方法就是构造方法,肯定是一个对象方法 - 减号开头
知识点2:重写init方法
1.每次创建Person对象出来都要保证变量age有个固定的值10
2.默认的init时父类NSObject的
3.command+双击类:快速进入类的头文件
4.在类实现.m文件里 重新实现init方法(不用写声明了,因为父类声明过了)
- (id)init//因为子类类型不确定
{
/*self=[super init] 1.一定要调用回super的init的方法;
是为了初始化当前super(对象的父类)中声明的成员变量和其他属性 ,返回就是当前对象self*/
if(self=[super init])
//*2 if(self)
//*1.if(self != nil)//nil是0 (写法:1→2→最简单)
{
//初始化成功,能进行下面的初始化赋值给变量
_age=10;
}
return self;//返回一个已经初始化完毕的对象
}
子类可以自己拓展自己的属性
//学生对象初始化后,年龄(父类的变量)就是10 学号就是1
- (id) init
{
if(self=[super init])
{
_no=1;
}
return self
}//学生最终拥有的成员变量:自己的,和所有父类的SObject是不能step into去方法的
1.构造方法,先会初始化父类的东西,再初始化自己的 从上到下 初始化
2.重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
3.注意点:在重写的init方法里先去调用父类的构造方法([super init]);;在进行子类内部成员变量的初始化
4.init方法的执行过程:isa 是动态改变的 总是指向当前调用者的类
知识点3:自定义构造方法
1.先写代码 在写右边中括号 会自动补齐
2.重写的init会把成员变量默认值定死,这样不好,最好是根据外界所传,默认值就是什么 这就引入了自定义的构造方法
3.规范:
1*一定是对象方法 - 开头
2*返回值一般是id类型
3*方法名一般以init开头
4*成员变量 以_下划线开头 特色
- (id)initWithName:(NSString *)name
{
if(self=[super init])
{
_name=name;
}
return self;
}
5.如果_name是父类通过@property生成的,就说明它使私有的,不能在子类直接使用
所以要通过setter和getter方法访问 改成 [self setAge:name]
(这样写优先在在子类找setAge方法)或者self.age; 或者 [super setAge:name]
- (id)initWithName:(NSString *)name andAge:(int) age
{
if(self=[super init])
{
_name=name;
_age=age;
}
return self;
}
6.一个子类方法想同时初始化父类的成员变量,要注意父类的成员变量能否直接访问,不能就用父类的setter和getter方法
- (id)initWithName:(NSString *)name andAge:(int) age
{
if(self=[super initWithName:name])//父类的属性交给父类去初始化,这样写比5的好处是,
//父类的成员变量变化不会影响子类的代码变化
{
_age=age;
}
return self;
}