OC语言 - 成员变量作用域 | #import和@class

■ 成员变量作用域

作用域主要分为四种

1. @public    公开:在有对象的前提下,任何地方都可以直接访问

2. @private  私有:只能在当前类的对象方法中才能直接访问

3. @protected   受保护:只能在当前类和子类的对象方法中访问

4. @package     框架级:作用域介于私有和公开之间,只要处于同一个框架中就可以直接通过变量名访问

注:在 .m 文件声明的成员变量,因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在此声明的成员变量是私有的,即使 .m 文件中的成员变量使用 @public 修饰也不起作用;同样地,在 .m 中定义的成员变量不能和头文件中的成员变量同名


■ 类的嵌套

代码示例:下面代码中 Car 嵌套了 Tyres

// - Tyres.h

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface Tyres : NSObject{
 4     NSString *_brand;// 品牌
 5     CGFloat   _size; // 尺寸
 6 }
 7 
 8 
 9 - (id)initWithBrand:(NSString *)brand;
10 - (id)initWithSize:(CGFloat)size;
11 - (id)initWithBrand:(NSString *)brand
12                size:(CGFloat)size;
13 
14 - (NSString *)brand;
15 - (CGFloat)size;
16 
17 - (void)turn;
18 - (void)setBrand:(NSString *)brand;
19 - (void)setSize:(CGFloat)size;
20 
21 @end

// - Tyres.m

 1 #import "Tyres.h"
 2 @implementation Tyres
 3 
 4 - (void)turn{
 5     NSLog(@"轮胎开转!");
 6 }
 7 
 8 - (id)initWithBrand:(NSString *)brand
 9                size:(CGFloat)size{
10 
11     _brand = brand;
12     _size = size;
13     return self;
14 }
15 
16 - (void)setBrand:(NSString *)brand{
17 
18     _brand = brand;
19 }
20 
21 - (NSString *)brand{
22 
23     return _brand;
24 }
25 
26 - (void)setSize:(CGFloat)size{
27 
28     _size = size;
29 }
30 - (CGFloat)size{
31 
32     return _size ;
33 }
34 
35 - (id)initWithBrand:(NSString *)brand{
36 
37     _brand = brand;
38     return self;
39 }
40 
41 - (id)initWithSize:(CGFloat)size{
42 
43     _size = size;
44     return self;
45 }
46 @end

// - Car.h

 1 #import <Foundation/Foundation.h>
 2 #import "Tyres.h" 
 3 
 4 @interface Car : NSObject{
 5     NSString *_brand;
 6     CGFloat   _price;
 7     NSString *_color;
 8     
 9     // Tyres
10     Tyres     *_tire;
11 }
12 
13 - (void)setTire:(Tyres *)tire;
14 - (Tyres *)tire;
15 
16 - (void)setBrand:(NSString *)brand;
17 - (NSString *)brand;
18 
19 - (void)setPrice:(CGFloat)price;
20 - (CGFloat)price;
21 
22 - (void)setColor:(NSString *)color;
23 - (NSString *)color;
24 
25 
26 @end

// - Car.m

 1 #import "Car.h"
 2 #import "Tyres.h"
 3 @implementation Car
 4 
 5 - (void)setTire:(Tyres *)tire{
 6     _tire = tire;
 7 }
 8 
 9 -(Tyres *) tire{
10     return _tire;
11 }
12 
13 - (void)setBrand:(NSString *)brand{
14     _brand = brand;
15 }
16 
17 - (NSString *)brand{
18     return _brand;
19 }
20 
21 - (void)setPrice:(CGFloat)price{
22     _price = price;
23 }
24 
25 - (CGFloat)price{
26     return _price;
27 }
28 
29 - (void)setColor:(NSString *)color{
30     _color = color;
31 }
32 
33 - (NSString *)color{
34     return _color;
35 }
36 
37 
38 @end

// - main.m:重复引用头文件

 1 #import <Foundation/Foundation.h>
 2 #import "Car.h"
 3 #import "Car.h"   // #import 只会导入一次
 4 #include "Tyres.h"
 5 #include "Tyres.h"// #include 不会进行头文件过滤:重复导入一个文件会就出现多次导入的问题
 6 // #import 可以认为是 C 语言中 #include 的改进版本,然而它是否能够得到改善仍然是一个争论的问题

■ #import | @class 

两者区别

1. #import 会包含这个类的所有信息:包括实体变量和方法;@class 只是告诉编译器,其后声明的名称是类的名称,编译的时告诉编译器:这仅仅是一个类名!我们在头文件中一般只需要知道被引用的类名就可以了,不需要知道其内部的实体变量和方法。所以在头文件中一般使用 @class 来声明类名,而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,就需要使用 #import

2. 在编译效率方面来讲,如果你有 100 个头文件都 #import 了同一个头文件,或者这些文件的引用关系如是 A–>B 且  B–>C 且  C–>D,那么当 D 文件有所变化,所有引用过到它的类 A、B、C 都需要重新编译!如果你的类有足够多,这将耗费大量的时间,而是用 @class 则不会产生这样的情况

3. 在循环依赖方面来讲,比如 A–>B 且  B–>A,使用 #import 相互包含就会出现编译错误,产生死循环的问题。而使用 @class 在两个类的头文件中相互声明,则不会有编译错误出现

代码示例:验证使用 #import 彼此引用头文件所产生的环依赖问题

// - Student.h

 1 #import <Foundation/Foundation.h>
 2 
 3 // 问题:两个类都如果都使用 #import 彼此引用,编译报错
 4 #import "StuClass.h"
 5 
 6 // 解决方式:任一方使用 @class 即可
 7 //@class StuClass;
 8 
 9 @interface Student : NSObject{
10     StuClass *_stuClass; // 报错原因:Unknown type name 'StuClass'
11 }
12 
13 @end

// - StuClass.h

1 #import <Foundation/Foundation.h>
2 
3 #import "Student.h"
4 @interface StuClass : NSObject{
5     Student *_student;
6 }
7 
8 @end

 

posted on 2018-08-07 09:44  低头捡石頭  阅读(69)  评论(0编辑  收藏  举报

导航