gpt4 book ai didi

ios - 复制 block

转载 作者:可可西里 更新时间:2023-11-01 04:41:55 26 4
gpt4 key购买 nike

有人能告诉我为什么 localComplete block 和 self.block 的内存地址相同吗? self.complete 的属性设置为复制,只是为了确保在将其分配给 self.complete 时我也在 localComplete 上调用复制。

- (void) test {

CompletionBlock localComplete = ^{

};

NSLog(@"localComplete - %p", localComplete);

self.block = [localComplete copy];

NSLog(@"self.complete - %p", self.block);

self.block();
}

这是输出:

2013-10-05 08:39:18.549 TestApp[90703:a0b] localComplete - 0x60b8
2013-10-05 08:39:18.550 TestApp[90703:a0b] self.complete - 0x60b8

作为另一个例子,我创建了字符串:

// creating string
self.carType = [[NSString alloc] initWithFormat: @"Good%@", @"year"];
NSLog(@"self.carType - %p", self.carType);

// same memory address???
NSString *carInitString = [[NSString alloc] initWithString: self.carType];
NSLog(@"carInitString - %p", carInitString);

// same memory address???
NSString *carCopy = [self.carType copy];
NSLog(@"carCopy - %p", carCopy);

// different memory address
NSString *carInitWithFormat = [[NSString alloc] initWithFormat: @"%@", self.carType];
NSLog(@"carInitWithFormat - %p", carInitWithFormat);

输出:

2013-10-05 09:45:01.667 TestApp[91103:a0b] self.carType - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitString - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carCopy - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitWithFormat - 0xa336b70

为什么 carInitString 和 carCopy 不是不同的内存地址?项目build设置中的优化已关闭。

最佳答案

关于您原来的问题, block 通常分配在堆栈上。复制 block (使用 Block_Copy 函数或 -copy 方法)将在堆栈上移动 block (进一步调用只会增加 block 的保留计数)

Block_copy [...], given a block pointer, either copies the underlying block object to the heap, setting its reference count to 1 and returning the new block pointer, or (if the block object is already on the heap) increases its reference count by 1

( source )

因此在您的示例中,您可能期望不同的地址,因为第一个 block 是本地的,而第二个 block 在堆上,但是因为该特定 block 没有对周围范围,编译器会将其标记为全局 block 。全局 block 不在堆栈上分配,而是在内存中的固定位置。

复制全局 block 不会将 block 移动到任何地方。它只会增加其保留计数,因为该对象已经在堆上。这就是您不会获得两个不同地址的原因。

尝试创建一个引用周围上下文的 block ,您将有两个不同的地址(堆栈和堆)。


现在,让我们来解决您关于 NSString 的问题。

复制一个不可变对象(immutable对象)可能导致retain作为优化(我的意思是,框架设计优化,编译器与它无关),这取决于类如何实现NSCopying 协议(protocol)。

许多基础类都是如此,例如 NSStringNSArrayNSSet...

这完全符合 NSCopying 协议(protocol)规范,您可以在 documentation 中阅读:

Your options for implementing this protocol are as follows:

...

  • Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.

正如 Greg Parker 在评论中指出的那样,-[NSString initWithString:] 执行相同类型的优化。如果您将不可变字符串作为参数传递,它只会保留并返回相同的字符串。


在某些情况下这是一种有用的行为,这里有一个例子:你声明一个属性

@property (nonatomic, copy) NSArray *anArray;

然后在界面中公开它。

将其声明为 copy 是一种很好的做法,可以确保您正在处理的对象以后不会被客户端更改。如果您只是保留它并且客户端传入一个 NSMutableArray,您将无法阻止她操作该对象。

所以复制是好的,但它似乎是有代价的:即使你不需要复制对象(即它是不可变的),你也会复制它。

但是,由于上述行为,您无需付出这样的代价。将 copy 发送到 NSArray 只会保留它,而将它发送到 NSMutableArray 将实际复制它,所以在这种情况下是一个巨大的胜利.

关于ios - 复制 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19199515/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com