弱房产的开销很大?

cba*_*tel 5 weak-references objective-c ios

在大约100,000次setDelegate调用之后,我的iOS应用程序在setDelegate上停顿了大约15秒.将委托属性从弱更改为分配可以解决问题.知道为什么弱的财产有这么多的开销并拖延应用程序?

我怀疑弱引用是在数组中维护的,因此运行时可以通过它们循环,并在委托对象被释放时将指针设置为nil.阵列是否有最大尺寸?当n接近100,000时,失速变得更长.

示例代码如下:

头文件:

#import <Foundation/Foundation.h>

@protocol GraphDataPointDelegate <NSObject>
- (BOOL)drawGraphByDistance;
@end

@interface GraphDataPoint : NSObject
- (id)initWithYValue:(NSNumber *)yValue withTime:(NSNumber *)time withDistance:(NSNumber *)distance withDelegate:(id <GraphDataPointDelegate> )delegate;
@end

@interface Graph : NSObject <GraphDataPointDelegate>
@end
Run Code Online (Sandbox Code Playgroud)

M文件

#import "Graph.h"

@interface GraphDataPoint ()

@property (nonatomic, weak, readwrite) id <GraphDataPointDelegate> delegate;
@property (nonatomic, strong, readwrite) NSNumber *yValue;
@property (nonatomic, strong, readwrite) NSNumber *time;
@property (nonatomic, strong, readwrite) NSNumber *distance;

@end

@implementation GraphDataPoint

- (id)initWithYValue:(NSNumber *)yValue withTime:(NSNumber *)time withDistance:(NSNumber *)distance withDelegate:(id<GraphDataPointDelegate>)delegate {
    self = [super init];
    if (self) {
        self.yValue = yValue;
        self.time = time;
        self.distance = distance;
        self.delegate = delegate;
    }
    return self;
}

- (id)graphXValue {
    if ([_delegate drawGraphByDistance]) {
        return _distance;
    } else {
        return _time;
    }
}

@end

@implementation Graph

- (id)init  {
    self = [super init];
    if (self) {

        NSMutableArray *array = [NSMutableArray array];
        NSLog(@"before");
        for (int i = 0; i < 100000; i++) {
            GraphDataPoint *graphData = [[GraphDataPoint alloc] initWithYValue:@1 withTime:@1 withDistance:@1 withDelegate:self];
            [array addObject:graphData];
        }
        NSLog(@"after");
    }
    return self;
}

- (BOOL)drawGraphByDistance {
    return YES;
}

@end
Run Code Online (Sandbox Code Playgroud)

Mec*_*cki 6

系统需要跟踪存储指向对象的弱指针的每个存储器地址.为什么?因为如果要释放对象(它的内存将被释放),所有这些指针必须设置为nilfirst.这就是使弱指针特殊的原因:它们不保留对象(不保持它们活着),但它们也永远不会悬挂指针(从不指向前者,现在死对象的内存地址); 如果物体死亡,它们就会变成nil.因此,每当弱引用的值发生变化时,系统必须首先告诉全局弱指针跟踪管理器删除过去记录的此内存地址信息(如果有),然后在更改对象后记录新信息.不用说,整个事情必须是线程安全的,因此涉及(稍微昂贵)锁定.

__weak id x;
// ...
x = anObject;
// ...
x = anotherObject;
// ....
x = nil;
Run Code Online (Sandbox Code Playgroud)

事实上(并非真的,只是为了得到概念):

__weak id x;
// ...
[WeakPointerTrackingManager lock];
x = anObject;
[WeakPointerTrackingManager var:&x pointsTo:anObject];
[WeakPointerTrackingManager unlock];
// ...
[WeakPointerTrackingManager lock];
x = anotherObject;
[WeakPointerTrackingManager var:&x pointsTo:anotherObject];
[WeakPointerTrackingManager unlock];
// ...
[WeakPointerTrackingManager lock];
x = nil;
[WeakPointerTrackingManager deleteInfoForVar:&x];
[WeakPointerTrackingManager unlock];
Run Code Online (Sandbox Code Playgroud)

assign没有那样做.只是存储对象的引用而不增加对象保留计数器.但是,如果对象死亡,assign变量仍然指向对象过去居住的内存地址.如果您现在向此不存在的对象发送消息,您的应用程序可能会崩溃或可能发生其他未定义的事情.

但严重的是,每个执行100,000次setDelegate调用的应用程序都被设计恕我直言.我想不出任何有意义的严重用例.在这里做任何你打算做的事情可能有更好的方法.

仅仅为了记录,访问弱变量也是昂贵的.

__weak id x;
// ...
[x sendMessage];
// ...
__strong id y; // Strong is optional, 
               // vars are strong by default
y = x;
Run Code Online (Sandbox Code Playgroud)

事实上(并非真的):

__weak id x;
// ...
__strong id tmp;
[WeakPointerTrackingManager lock];
tmp = [x retain];
[WeakPointerTrackingManager unlock];
[tmp sendMessage];
[tmp release];
// ...
__strong id y;
[WeakPointerTrackingManager lock];
y = [x retain];
[WeakPointerTrackingManager unlock];
Run Code Online (Sandbox Code Playgroud)