gpt4 book ai didi

objective-c - 启用 ARC 后出现奇怪的内存问题

转载 作者:行者123 更新时间:2023-12-03 17:30:24 25 4
gpt4 key购买 nike

我遇到了一个非常非常奇怪的错误,可能与内存管理有关(即使我使用的是 ARC)。

我有一个 AppDelegate、Foo 和 SubFoo(它是 Foo 的子类)。

Foo.h

@protocol FooDelegate <NSObject>

- (void)didReceiveDownloadRequest:(NSURLRequest *)downloadRequest;

@end

@interface Foo : NSObject {
__weak id <FooDelegate> delegate;
}

- (void)performRequest;

@property (nonatomic, weak) id <FooDelegate> delegate;
@property (nonatomic, retain) NSString *fileIdentifier;

Foo.m

@implementation Foo

@synthesize delegate, fileIdentifier;

- (id)init {
if ((self = [super init])) {
self.delegate = nil; // I tried leaving this line out, same result.
NSLog(@"I am %p.", self);
}

return self;
}

- (void)performRequest {
// Bah.
}

@end

SubFoo.h

@interface SubFoo : Foo {
WebView *aWebView;
}

SubFoo.m

- (void)performRequest {
if (self.fileIdentifier) {
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"theURL"]];
}
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSLog(@"Finished loading.");

// ...

NSLog(@"Class Name: %@", NSStringFromClass([self class]));
NSLog(@"Memory Location of delegate: %p", self.delegate);

// ...
}
有时,webView上的类名:didFinishLoadForFrame:返回一个完全不同的类(而不是SubFoo,它返回随机类,如NSSet,NSArray,有时甚至返回CFXPreferencesSearchListSource),其他时候它只是崩溃并出现EXC_BAD_ACCESS,当它返回类名上的随机类时:它返回 [randomClassName delegate] 是一个无法识别的选择器。

编辑:当 self 设置为另一个事物时,它会在 webView:didFinishLoadForFrame: 上设置为正确,并且在 PerformRequest 上它始终为 SubFoo。

如有任何帮助,我们将不胜感激。

最佳答案

首先,即使您在项目中使用 ARC 清零弱引用 (@property (weak)),其他项目和框架也可能不会(也很可能不会)使用清零弱引用。

换句话说,假设框架中的所有委托(delegate)都是__unsafe_unretained,除非:

  1. 委托(delegate)属性在 header 中声明为weak
  2. 文档/标题明确说明了其他情况
<小时/>

也就是说,让我们来谈谈你的例子。您的对象所有权图表如下所示:

Object ownership chart

(注意:我不完全确定您的项目中的哪个类使用了 SubFoo。根据惯例,我假设您有一个对 SubFoo 具有强引用的类,并且该类也设置为一个 SubFooDelegate)

最终,您的 SubFoo 实例将失去其最后一个强引用并正在释放。在完美的启用 ARC 的世界中,WebView 指向 SubFoo 的指针此时将为零。然而,这还不是一个完美的世界,WebView 的frameLoadDelegate 是__unsafe_unretained。由于运行循环交互,WebView 的生命周期比 SubFoo 长。 Web 请求完成,死指针被取消引用。

要解决此问题,您需要在 SubFoo 的 dealloc 方法中调用 [aWebView setFrameLoadDelegate:nil];。当您重新分配 aWebView 时,您还需要调用它,因为您将失去对旧 aWebView 的跟踪:

SubFoo.m

@implementation SubFoo

- (void)dealloc {
[aWebView setFrameLoadDelegate:nil];
// Also nil out any other unsafe-unretained references
}

- (void)performRequest {
if (self.fileIdentifier) {
[aWebView setFrameLoadDelegate:nil]; // Protects us if performRequest is called twice. Is a no-op if aWebView is nil
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"theURL"]];
}
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
// ...
}

关于objective-c - 启用 ARC 后出现奇怪的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9741697/

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