ios 私有变量的发展历史以及self. 和 _的区别
来源:互联网 发布:视频特效制作软件哪些 编辑:程序博客网 时间:2024/06/06 17:33
在 Objective-C 的语言的早期,类的私有成员变量是只能定义在 .h 的头文件里面的。像如下这样:
- @interface ViewController : UIViewController {
- @private
- NSInteger _value;
- }
之后,苹果改进了 Objective-C,允许在 .m 里面添加一个特殊的匿名 Category(扩展),即没有名字的 Category,来实现增加类的成员变量。像如下这样:
- @interface ViewController ()
- @property (nonatomic) NSInteger value;
- @end
这样的好处是,这些变量在头文件中被彻底隐藏起来了,不用暴露给使用者。
接着,在 2013 年的 WWDC 中,苹果进一步改进了 Objective-C,允许在 .m 的 @implementation 中直接添加类的私有成员变量。像如下这样:
- @implementation ViewController {
- NSInteger _value;
- }
其中最常用的方式是第二种。首先通过self.xxx 访问属性的方法包含了set和get方法。而通过下划线是获取自己的实例变量,不包含set和get的方法。
例如:
@property (nonatomic,copy) NSString *propertyName;self.propertyName 是对属性的访问;
_propertyName 是对局部变量的访问。
@property的声明中,编译器在生成getter,setter方法时是有优先级的,它首先查找当前的类中用户是否已定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。 无论怎样你在使用self.propertyName 时是都在调用一个getter方法。self.propertyName 会让计数器+1;
而_propertyName,是直接调用变量,不通过getter方法。
_propertyName是类似于self->_propertyName。
所以使用self.xxx是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下滑线的时候忽略了self这个指针,后者容易在BLock中造成循环引用。另外,使用下划线是获取不到父类的属性。
最后总结:self方法实际上是用了get和set方法间接调用,下划线方法是直接对变量操作。
下面是例子代码和注释:
#import <Foundation/Foundation.h>
@interface MethodDetailMusic : NSObject {
@public NSString *publicStr;
}
- (void)initPrivateString;
- (void)initPrivateString2;
- (void)initStr2;
@end
#import "MethodDetailMusic.h"
//_propertyName 是对局部变量的访问, 是直接调用变量,不通过getter方法,他的使用方法类似于 self->_propertyName. self.propertyName 是对属性的访问,在调用一个getter方法。self.propertyName 会让计数器+1;
@interface MethodDetailMusic () {
//private string 这里有花括号,发现无法声明属性变量, 即这一作用域的声明仅仅限定于实例变量的声明,即没有setter和getter方法
@private NSString *specialPrivateString;
NSString *str ;
}
//在interface中花括号外声明的只能是属性变量,即有setter和getter方法,系统自动带上了,这里也可以达到私有变量的效果,也是目前最常用的一种声明所谓私有化的变量,但是实际上
//是没有所谓的私有化的变量的,因为可以利用kvo在外部进行值的改变
@property (nonatomic, strong) NSString * str2;
- (void)createPrivateFunction;
@end
@implementation MethodDetailMusic {
//另外一种在@implementation中定义实例变量的方式,同样的不能在这里声明属性变量
NSString *privateTestString2;
}
- (void)createPrivateFunction {
}
- (void)initPrivateString {
//实例变量的访问,不能使用self.访问符号,但是可以使用_因为specialPrivateString不是属性变量而是实例变量,所以不能使用self. 也不能_ 会报错
if (!specialPrivateString) {
specialPrivateString = @"我是私有变量";
}
NSLog(@"%@", specialPrivateString);
}
- (void)initPrivateString2 {
if (!privateTestString2) {
privateTestString2 = @"我是私有变量2";
}
NSLog(@"%@", privateTestString2);
}
- (void)initStr2 {
if (!self.str2) {
self.str2 = @"我是私有变量3";
}
NSLog(@"%@", self.str2);
}
#import "ViewController.h"
#import "MethodDetailMusic.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self test];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)test {
MethodDetailMusic *music = [[MethodDetailMusic alloc] init];
[music initPrivateString];
//kvc 键值编码可以修改私有变量
[music setValue:@"修改私有变量" forKey:@"specialPrivateString"];
[music initPrivateString];
//定义一个实例变量 privateString 通过底层runtime 获取实例变量Ivar 对应私有值
Ivar privateString = class_getInstanceVariable([music class], "specialPrivateString");
NSString *privateStr = object_getIvar(music, privateString);
NSLog(@"打印私有变量===%@",privateStr);
//第二种私有变量的方式
[music initPrivateString2];
[music setValue:@"修改私有变量2" forKey:@"privateTestString2"];
[music initPrivateString2];
//定义一个实例变量 privateString 通过底层runtime 获取实例变量Ivar 对应私有值
Ivar privateString2 = class_getInstanceVariable([music class], "privateTestString2");
NSString *privateStr2 = object_getIvar(music, privateString2);
NSLog(@"打印私有变量2===%@",privateStr2);
//外部访问定义私有的属性变量
[music initStr2];
[music setValue:@"修改私有属性变量" forKey:@"str2"];
[music initStr2];
//定义一个实例变量 privateString 通过底层runtime 获取实例变量Ivar
//在这里会发现打印出来的是null,因为str2不是实例变量,而是属性变量
Ivar privateString3 = class_getInstanceVariable([music class], "str2");
NSString *privateStr3 = object_getIvar(music, privateString3);
NSLog(@"打印私有变量3===%@",privateStr3);
}
- ios 私有变量的发展历史以及self. 和 _的区别
- IOS 中self. 和_访问变量的区别
- ObjectiveC中的self.变量和_变量的区别
- self.方法和_对变量的引用的区别
- 【IOS之内存管理】self.变量 和 变量 的区别
- unix linux的历史、区别以及发展
- self 和 _的区别
- iOS中_(下划线)和self.的区别
- self.和_的区别(self和下划线的区别)
- ios中有self和无self的变量的区别
- self.***和_***的使用和区别
- ios self.和下划线的区别
- iOS中self.和下划线的区别
- iOS中self.和下划线的区别
- iOS中self.和下划线的区别
- IOS self.xxx和_xxx的区别
- ios开发self和super的区别
- iOS中self和下划线的区别
- 第15周||排序算法的基础应用及其验证(1)
- 【第八周】项目3-顺序串算法
- Python 面向对象类概念介绍
- Android Studio 使用NDK编译Protobuf为so库
- 第十周项目1(1)-层次遍历算法的验证
- ios 私有变量的发展历史以及self. 和 _的区别
- UE4 C++编程常用知识点总结
- bootstrap中col-xs-*和col-sm-* 和col-md-*
- SSM+Shiro
- Centreon 安装部署指南++
- MAVEN的安装
- 打开回闪特性
- 第十五周项目1 验证算法(2)插入排序之希尔排序
- 第八周 项目三 — 对称矩阵压缩存储的实现与应用(2)