一、实例变量可见度

可见度 特点

public 实例变量可以在类的外部和内部操作

protected 实例变量只能在该类和其子类内操作 默认

private 实例变量只能在该类内访问

内部:相应类的@implementation和@end之间


@interface Person : NSObject

{

@public

NSString*_name;

@protected

NSString*_gender;

int_age; //年龄

@private

NSString*_age;

}

mian.m文件中使用

Person * p = [[Person alloc] init];
p->_name = @"zhangyixing";
// p->_gender = @'m'; // 警告
// p->_age = 18; // 警告


为什么不使用@public 暴露细节 不符合封装

在其他文件访问@protected修饰的实例变量-----方法

提示:添加两个方法。

赋值:通过方法传入参数,在类的内部实现实例变量赋值。

取值:通过方法获取实例变量的值。


二、方法--方法类型、返回值类型、方法名、参数列表

OC中的方法------类方法、实例方法

同一个中,所有的类方法中不能出现重名 所有的实例方法中不能出现重名

1、 类方法:只能类使用 [类名 类方法名]

在类方法中不能使用实例变量 调用类方法时没有创建对象

声明-----Person.h

+ (void)sayHi;

实现-----Person.m

+ (void)sayHi
{
NSLog(@"hi");
}

2、实例方法:只能对象使用 [对象 实例方法名]

声明-----Person.h

- (void)sayHello;

实现-----Person.m

- (void)sayHello
{
NSLog(@"hello");
}

3、声明方法 (返回值类型)没有参数只写方法名

(1)无返回值、无参数
- (void)sleep;

实现

- (void)sleep
{
NSLog(@"sleep");
}

使用

[p sleep];


(2)无返回值、有参数

语法--- :(参数类型)参数名

参数以:开头 ":"标识参数,不能省略。有冒号必须有参数

///// 一个参数

- (void)eat:(NSString *)food;

实现

- (void)eat:(NSString *)food
{
NSLog(@"%@",food);

}

使用

[p eat:@"beef"];


///// 两个参数

- (void)setName:(NSString *)name age:(NSInteger)age; // 赋值

实现

- (void)setName:(NSString *)name age:(NSInteger)age
{
_name = name;
_age = age;

// name和age是方法的形参,接收从外部传入的值
}

使用

[p setName:@"zhangyixing" age:18];

(3) 有返回值、无参数
- (NSString *)getName; // 取值

实现

- (NSString *)getName
{
return _name;
}

使用

NSLog(@"name=%@",[p getName]);

// 方法名使用驼峰命名法---方法名: setName:age:

首字母小写;第一个参数修饰符首字母大写;

第二个首字母小写;都使用驼峰命名法


4、方法使用----[person sayHi];

在OC中没有”student调用sayHi“这种表述。

在OC中使用消息发送机制:[receiver message]。

正确表述:给student对象发送sayHi消息。

1)student接收到消息,即方法sayHi;

2)student找到sayHi方法,并执行。


三、setter、getter

1、简述

在OC里,为实例变量赋值的方法称作setter(设置器)。

读取实例变量值的方法称作getter(访问器)。

我们之前写的那些赋值取值的方法都可以称作setter和getter。

2、实例

(1)设置_name实例变量的值
// setter方法是实例方法,没有返回值,只有一个参数
// 方法名 set + 实例变量名(忽略_,使用驼峰命名法)
// 参数 跟操作的实例变量有关 类型跟操作的实例变量一致 实例变量名(忽略_)
- (void)setName:(NSString *)name;
实现

- (void)setName:(NSString *)name
{
_name = name;

// name是方法的形参,接收从外部传入的值 _name实例变量
}

(2)访问实例变量
// getter是实例方法 没有参数 返回值类型与操作的实例变量保持一致
// 方法名 实例变量名(忽略_) 切记:不要以get开头
- (NSString *)name;

实现

- (NSString *)name
{
return _name;
}

(3)使用

// 使用setter方法给Person对象的实例变量_name赋值
[p setName:@"zhang"];
// 使用getter方法读取实例变量的值
NSLog(@"name = %@", [p name]);


3、与实例变量的关系

无论setter还是getter内部操作的是实例变量

每个实例变量都需要一对setter和getter方法

4、main.m文件中使用

// 使用setter方法给Person对象的实例变量_name 和_age赋值
[p setName:@"zhang"];
[p setAge:23];
// 使用getter方法读取实例变量的值
NSLog(@"name = %@, age = %ld", [p name], [p age]);


四、自定义初始化方法

-(id)init这个初始化方法只能给实例变量设置默认值,不灵活

- (id)init
{
return self;
}

-(id)initWithName:自定义初始化法,根据需求定义初始化方法

// 自定义初始化方法 初始化对象时给_name和_age赋值
- (id)initWithname:(NSString *)name age:(NSInteger)age;

实现

- (id)initWithname:(NSString *)name age:(NSInteger)age
{
// 对象初始化时可以传入姓名和年龄 将传入的值赋值给实例变量
_name = name;
_age = age;
return self;
}


main.m文件中使用

Person * p3 = [[Person alloc] initWithname:@"zhangyixing" age:18];
Person * p4 = [[Person alloc] initWithname:@"liyifeng" age:20];
NSLog(@"name=%@",[p3 name]);
[p4 setName:@"liminhao"];
NSLog(@"name=%@",[p4 name]);


五、导入文件

1、#import导入头件,即:导入头件中的内容到当前类。

#import “”导入自定义类,自己创建的文件 从当前工程目录开始查询

#import <> 导入类库中的头文件,自己创建的文件 从当前工程目录开始查询

功能类似C语言中的#include,但是可以避免头文件被重复导入。

容易出现循环导入头文件问题。

2、#include 和 #import的区别

(1)include不能重复导入同一个文件
(2)import可以重复导入同一个文件

3、@class

#import可能会造成循环导入头文件问题,需要使用@class解决

@class的作用,告知编译器系统class后面的标识符可以作为一个类名使用;并没有导入这个类的内容

使用@class可以解决循环导入头文件的问题。

如果需要在类的接口部分使用其他类型:

1)在.h文件中,使用@class声明需要使用的类型;

2)在.m文件中,使用#import导入需要使用的类型


实例

创建Man、Woman、Child三个类并完成声明与实现部分

新创建Family类

Family.h文件

#import <Foundation/Foundation.h>

// 使用@class“导入”文件

@class Man;
@class Woman;
@class Child;

@interface Family : NSObject

// 定义实例变量

{
Man * _father;
Woman * _mother;
Child * _kid;
}
// 初始化方法设置father和mother
- (id)initWithFather:(Man *)father mother:(Woman *)mother;
// 声明setter、getter方法
- (void)setFather:(Man *)father;
- (Man *)father;
- (void)setMother:(Woman *)mother;
- (Woman *)mother;
- (void)setKid:(Child *)kid;
- (Child *)kid;
// 声明一般方法
- (void)introduce;


Family.m文件

#import "Family.h"
导入文件
#import "Man.h"
#import "Woman.h"
#import "Child.h"
@implementation Family
// 初始化方法设置father和mother
- (id)initWithFather:(Man *)father mother:(Woman *)mother
{
_father = father;
_mother = mother;
return self;
}
// 实现setter、getter方法
- (void)setFather:(Man *)father
{
_father = father;
}
- (Man *)father
{
return _father;
}
- (void)setMother:(Woman *)mother
{
_mother = mother;
}
- (Woman *)mother
{
return _mother;
}
- (void)setKid:(Child *)kid
{
_kid = kid;
}
- (Child *)kid
{
return _kid;
}
// 实现一般方法
- (void)introduce
{
NSLog(@"father:%@,mother:%ld,kid:%@", [_father name], [_mother age], [_kid gender]);
}

main.m文件

#import <Foundation/Foundation.h>

// 导入文件

#import "Man.h"
#import "Woman.h"
#import "Child.h"
#import "Family.h"


Man * m = [[Man alloc] initWithName:@"zhangjiashuai"];
Woman * w = [[Woman alloc] initWithName:@"zhangjiamei" age:18];

Family * f = [[Family alloc] initWithFather:m mother:w];

Child * c = [[Child alloc] initWithName:@"zhangyi" gender:@"m"];
[f setKid:c];
[f introduce];


六、总结

1、实例变量有3种常见的可见度:@public、@protected、@private。

@public违背了封装特性,面向对象开发中很少使用;

@protected默认可见度,自己和子类中能使用—>访问实例变量;

@private自己类中能使用—>访问实例变量。

2、方法是OC的核心,采用消息机制:[receiver message]。

“-”message由对象来调用;

“+”message由类来调用。