OC里面给变量赋值有2种方法第一种是直接用下划线的,也就是实例变量:_button= 第二种是使用属性:self.button
= ....这两种有何区别???
以下项目是创建了一个C++项目 简单模拟创建对象和给变量赋值的情况
首先创建了一个NSObject类,在OC里面继承NSObject类的都有retain release autorelease。。。。等方法来管理内存的
NSObject的头文件,声明方法
// // NSObject.h // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #ifndef __autorelease__NSObject__ #define __autorelease__NSObject__ #include <iostream> class NSObject{ int m_retainCount;//计数器 //这里面应该还有一个自动释放池的对象 public: //加1 void retain(); //减1 void release(); //自动释放 void autorelease(); //计数器的getter方法 int retainCount(); }; #endif /* defined(__autorelease__NSObject__) */
NSObject的实现文件.cpp 里面实现了头文件里面声明的方法
// // NSObject.cpp // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #include "NSObject.h" using namespace std; //加1 void NSObject:: retain(){ m_retainCount++; } //减1 void NSObject:: release(){ //如果当前对象不为空 并且引用计数器大于0 if (this !=nullptr && m_retainCount > 0) { m_retainCount--; } } //自动释放 void NSObject:: autorelease(){ //把当前对象添加到自动释放池当中 延迟release //当自动释放池对象释放的时候,会把里面保存的对象全部release一次 //这里只是简单模拟,没有延迟释放 m_retainCount--; } //计数器的getter方法 int NSObject:: retainCount(){ return m_retainCount; }
接着创建UIButton类继承于NSObject类
头文件
// // UIButton.h // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #ifndef __autorelease__UIButton__ #define __autorelease__UIButton__ #include <iostream> #include "NSObject.h" class UIButton:public NSObject{ public: //创建对象 static UIButton* button(); //初始化方法 void init(); }; #endif /* defined(__autorelease__UIButton__) */
UIButton类的实现文件.cpp
// // UIButton.cpp // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #include "UIButton.h" using namespace std; //创建对象 UIButton* UIButton:: button(){ //开辟内存空间 UIButton* btn = new UIButton;//OC的这一步是alloc会导致引用计数器加1,而C++这一步没办法加1 btn->retain(); btn->init(); //实际上这三步就相当于OC里面的[[..alloc]init] //现在是btn指针加1 注意 内存管理 谁加谁减。如果在这里直接release那么返回的可能就没有了,如果不release的话,btn这个指针在栈里出了这个方法就会弹栈了 就找不到btn了.....所以把它放在自动释放池里面,这样出了这个方法还能用,也不用考虑内存管理的问题 btn->autorelease(); return btn; } //初始化方法 void UIButton:: init(){ } //OC里面给变量赋值有2种方法 第一:_button 第二:self.button // 创建对象 这里UIButton* button相当于_button = ... // UIButton* button = UIButton::button();//现在button引用计数器为1 因为autorelease还没有执行 如果不考虑延迟释放的问题,其实质上为0了。因为UIButton::button()里面加1 也减1了 //也就是说button的计数器为0 在这个方法里面可以用,出了这个方法就访问不到button了
最后创建一个MyClass类 也是继承NSObject
头文件
// // MyClass.h // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #ifndef __autorelease__MyClass__ #define __autorelease__MyClass__ #include <iostream> #include "UIButton.h" //在OC里面声明一个属性,编译器会帮你做几件事呢??会生成一个保护的(实例)变量,还会生成2个公开的方法setter getter class MyClass : public NSObject{ public://公有的 void setButton(UIButton* button); UIButton* getButton(); // void setButton2(UIButton* button); UIButton* getButton2(); //初始化方法 void init();//初始化方法里把保护的_button指针创建出来让它指向一个对象 protected://保护的 UIButton* _button; UIButton* _button2; private://私有的 }; #endif /* defined(__autorelease__MyClass__) */
MyClass类的实现文件.cpp
// // MyClass.cpp // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #include "MyClass.h" using namespace std; void MyClass:: init(){ //在OC里面可以直接使用下划线创建对象 _button = UIButton::button();//这种创建的对象出来引用计数器为0 cout << "使用下划线创建对象的计数器为: " << _button->retainCount() << endl; //在OC里面还可以这样 self.相当于调用了button的setter方法 //self.button = UIButton::button();//这样的计数器为1 //在C++里面应该怎样呢? this->setButton(UIButton::button()); cout << "使用setter方法创建对象的计数器为: " << _button->retainCount() << endl; this->setButton2(UIButton::button());//相当于self.button2 = ....//现在button2的引用计数器应该也为1 cout << "button2 count: " << _button2->retainCount() << endl; UIButton *but = _button;//指向_button cout << "=== 赋值之前button1 button2的引用计数器都为1 ===" << endl; //调用button1的方法 this->setButton(_button2); //相当于self.button = _button2; #pragma 注意执行完这句之后_button也是指向了_button2对象了 cout << "button1 count: " << _button->retainCount() << endl;//实际上是调用button2的retainCount cout << "button2 count: " << _button2->retainCount() << endl; cout << "_button原来指向的那个对象的引用计数器为: " << but->retainCount() << endl; //出了方法就会被销毁 #pragma _button2要怎么释放? 现在_button 和_button2 都在用它 //谁不用 谁减 _button->release(); cout << _button->retainCount() << endl; _button2->release(); cout << _button2->retainCount() << endl;//到这里_button2的引用计数器为0了出了方法就会被销毁 } #pragma mark - button 的setter getter方法 void MyClass:: setButton(UIButton* button){ //1.判断是否自己负值 if (_button == button) { return;//如果是自己给自己赋值 那就不用操作 }else{ //如果不是 //2.先释放原有内存空间 在OC里面对已经是0的计数器再release也没关系 _button->release(); //A-1 //3.赋值操作 _button = button; //A = B //4.retain _button->retain(); //B++ } } UIButton* MyClass:: getButton(){ return _button; } #pragma mark - button2的setter getter方法 void MyClass:: setButton2(UIButton* button){ if (_button2 == button) { return; }else{ //2.先释放原有内存空间 在OC里面对已经是0的计数器再release也没关系 _button2->release(); //3.赋值操作 _button2 = button; //4.retain _button2->retain(); } } UIButton* MyClass:: getButton2(){ return _button2; }
在主函数里面创建MyClass对象
// // main.cpp // autorelease // // Created by 06 on 15/1/24. // Copyright (c) 2015年 黄永锐. All rights reserved. // #include <iostream> #include "MyClass.h" using namespace std; int main(int argc, const char * argv[]) { MyClass* myclass = new MyClass; myclass->init(); //从输出结果可以看出,使用下划线创建对象的引用计数器为0. 使用setter方法创建的对象引用计数器为1 return 0; }
运行结果如下:
使用下划线创建对象的计数器为: 0 使用setter方法创建对象的计数器为: 1 button2 count: 1 === 赋值之前button1 button2的引用计数器都为1 === button1 count: 2 button2 count: 2 _button原来指向的那个对象的引用计数器为: 0 1 0 Program ended with exit code: 0
/////////////////////////////// ======= 额外 ======== ////////////////////////////////////
数组里面也会给元素加 1
。
数组里面为什么只能放对象??就是因为加 1
数组addObject一个元素进数组的时候,数组会负责给传进来的元素加1。
为什么数组要加1??谁用谁加。把元素放进数组里,也就是数组要用。
怎么加?
会调用你传进来的那个元素的retain方法,但是你的这个对象没有继承NSObject,不存在retain方法,就会出现问题了。例如传进一个int
100; 100根本就没有retain方法。 所以要把int封装成NSNumber类型,因为NSNumber继承NSObject
数组addObject的时候会加1 ,
那么什么时候会减1??
它用它加,不用了remove的时候会减1.
另外一种情况:不断的往数组里面添加元素,现在数组要销毁了,在销毁之前并没有全部remove
会不会有内存泄漏??
也不会,因为数组先把它里面所有的元素都release一次,自己才销毁.