oc82--成员变量使用copy修饰

简介:
复制代码
//
//  Person.h

#import <Foundation/Foundation.h>


typedef void (^myBlock)();

@interface Person : NSObject

//@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *name;

// 注意: 如果是block使用copy并不是拷贝, 将pBlock所指向的代码块从栈转移到堆中。block在堆中,使用外界对象的时候,会对外界对象的计数器加1,
@property (nonatomic, copy) myBlock pBlock;
//@property (nonatomic, retain) myBlock pBlock;
@end
复制代码
复制代码
//
//  Person.m

#import "Person.h"

@implementation Person

- (void)dealloc
{
    // 由于block使用外界对象会对里面的对象加1,因此要在Person释放的时候把里面使用的对象也释放。
    // 只要给block发送一条release消息, block中使用到的对象d也会收到该消息。
    Block_release(_pBlock);
    NSLog(@"%s", __func__);
    [super dealloc];
}
@end
复制代码
复制代码
//  Dog.h

#import <Foundation/Foundation.h>

@interface Dog : NSObject

@end
复制代码
复制代码
//  Dog.m

#import "Dog.h"

@implementation Dog

- (void)dealloc
{
    NSLog(@"%s", __func__);
    [super dealloc];
}
@end
复制代码
复制代码
//  main.m
//  Copy与string,block的结合使用

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"

int main(int argc, const char * argv[]) {
    
    // 1.copy的第一个用途, 防止外界修改内部的数据
    NSMutableString *temp1 = [NSMutableString stringWithFormat:@"lnj"];
    Person *p1 = [[Person alloc] init];
    p1.name = temp1;  //p1.name是一个新的对象,
    // 问题: 修改了外面的变量, 影响到了对象中的属性,记住: 以后字符串属性都用copy
    [temp1 appendString:@" cool"];
    NSLog(@"name = %@", p1.name);//lnj
    
    
    
    __block int num = 10;//block的本质是传了指针。才能修改外面的变量。
    void (^myBlock1)() = ^{
        num = 20;
        NSLog(@"%i", num);
    };
    myBlock1();// 20
    
    
    
    // block默认存储在栈中, 栈中的block访问到了外界的对象, 不会对对象进行retain
    // block如果在堆中, 如果在block中访问了外界的对象, 会对外界的对象进行一次retain
    Person *p2 = [[Person alloc] init];
    NSLog(@"retainCount = %lu", [p2 retainCount]);//1
    void (^myBlock)() = ^{
        NSLog(@"%@", p2);
        NSLog(@"retainCount = %lu", [p2 retainCount]);
    };
    myBlock();// retainCount = 1
    Block_copy(myBlock); // 将block转移到堆中
    myBlock();// retainCount = 2
    
    
    
    
    // 2.可以使用copy保存block, 这样可以保住block中使用的外界对象的命
    // 避免以后调用block的时候, 外界的对象已经释放了
    /*__block*/ Dog *d = [[Dog alloc] init]; // 1
    NSLog(@"Dog retainCount = %lu", [d retainCount]);// 1
    Person *p3 = [[Person alloc] init];
    p3.pBlock = ^{
        //2,block在堆中,使用外界对象的时候,会对d的计数器加1,Dog前面加了__block,block里面使用dog也不会对dog加1,
        NSLog(@"%@", d);
    };
    NSLog(@"Dog retainCount = %lu", [d retainCount]); // 2
    // 如果狗在调用block之前释放了, 那么程序就会崩溃
    [d release]; // 1
    p3.pBlock();
    [p3 release];
    
    
    
    // 3.注意点: copy block之后引发循环引用。
    // 如果对象中的block又用到了对象自己, 那么为了避免内存泄露, 应该将对象修饰为__block。
    __block Person *p = [[Person alloc] init]; // 1
    p.name = @"lnj";
    NSLog(@"retainCount = %lu", [p retainCount]);
    p.pBlock = ^{//由于是copy,所以这段代码在堆中,
        NSLog(@"name = %@", p.name); // 2,由于内部用到了外部对象p,对p加1,所以p为2,所以p前面要加__block,block里面就不会对外部对象加1,
    };
    NSLog(@"retainCount = %lu", [p retainCount]);
    
    p.pBlock();
    
    [p release]; // 1,p始终是1,无法释放。
    [p release]; // 2B
    
    return 0;
}
复制代码

 3的图片内存示意图

pBlock指向的是堆中的代码块地址。



本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/7442955.html,如需转载请自行联系原作者

相关文章
|
10天前
|
C++
C++ 实现一个不能被copy的类
C++ 实现一个不能被copy的类
|
2月前
|
存储 设计模式 算法
[C++] static静态成员变量/函数的用法
[C++] static静态成员变量/函数的用法
44 1
|
Java Kotlin
Kotlin data数据类、copy()函数、sealed密封类
Kotlin data数据类、copy()函数、sealed密封类使用
131 0
|
安全 编译器 C++
C++:类中const修饰的成员函数
C++:类中const修饰的成员函数
|
存储 Java
java中final修饰符,修饰变量、方法、类的详细用法
java中final修饰符,修饰变量、方法、类的详细用法
105 0
|
iOS开发
iOS开发 - 不用copy修饰的字符串属性什么情况下不安全
iOS开发 - 不用copy修饰的字符串属性什么情况下不安全
74 0
|
存储 API 对象存储
OC:在分类中添加成员变量,原来帮我们做了那么多事
本篇文章告诉你,如果在类对象和Category对象中添加一个属性时,底层做了什么。关联对象如何给Category对象添加成员变量,关联对象的实现原理。
185 0
OC:在分类中添加成员变量,原来帮我们做了那么多事
为什么要优先使用copy声明NSString属性?
至于为什么要优先使用copy声明NSString属性?首先科普一下:对象在内存中都有一个入口地址,当我们取到这个对象的地址(也就是指针),可以去改变这个对象的一些属性值,而当我们再次去取这个对象,使用这个对象的属性值(我们已修改过的)时,我们会发现这个值确实变成了我们修改的值,当然,前提是需要这个对象没有被销毁,在内存中还存在。选择使用copy的理由是:NSString属性可能被传入一个NSString实例,也可能是一个NSMutableString实例。当传入了一个NSMutableString实例时,字符串的值可能会在背后悄悄变化。