gpt4 book ai didi

objective-c - 基于 ARC 的应用程序中的过早释放

转载 作者:太空狗 更新时间:2023-10-30 03:52:10 24 4
gpt4 key购买 nike

我有一个问题,似乎是在基于 ARC 的应用程序中过早释放了一个正在使用的对象。我正在尝试在 FTP 服务器上创建一个文件夹。代码的相关部分如下;我会先描述问题。

代码的问题在于,

中的调试输出
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

方法永远不会被调用。

相反,我只是收到 _EXC_BAD_ACCESS_ 错误。在调试时我发现了两件事:

  1. 仅当执行以下代码行(createDir 方法)时才会出现该错误:

    [ftpStream open];

如果该消息未发送,则其余代码实际上没有任何意义 - 但它也不会崩溃...

  1. 我使用 NSZombieEnabled 跟踪了 EXC_BAD_ACCESS:启用僵尸对象后,GDB 生成以下调试器信息:

     *** -[FTPUploads respondsToSelector:]: message sent to deallocated instance 0x9166590

引用的地址 0x9166590 是我的 FTPUploads 对象的地址。看起来流委托(delegate)在它可以处理消息之前被释放了。

为什么系统会释放正在使用的对象?我怎样才能防止它被过早释放?

代码:

FTPUploads.h 摘录:

#import <Foundation/Foundation.h>

enum UploadMode {

UploadModeCreateDir,
UploadModeUploadeData
};

@class UploadDatasetVC;

@interface FTPUploads : NSObject<NSStreamDelegate> {

@private
NSString *uploadDir;
NSString *ftpUser;
NSString *ftpPass;

NSString *datasetDir;
NSArray *files;

/* FTP Upload fields */
NSInputStream *fileStream;
NSOutputStream *ftpStream;
// some more fields...
enum UploadMode uploadMode;
UploadDatasetVC *callback;
}

- (id) initWithTimeseriesID: (int) aTimeseriesID
fromDatasetDir: (NSString *) aDir
withFiles: (NSArray *) filesArg
andCallbackObject: (UploadDatasetVC *) aCallback;

- (void) createDir;

@end

FTPUploads.m 摘录

#import "FTPUploads.h"
#import "UploadDatasetVC"

@implementation FTPUploads

- (id) initWithTimeseriesID: (int) aTimeseriesID
fromDatasetDir: (NSString *) aDir
withFiles: (NSArray *) filesArg
andCallbackObject: (UploadDatasetVC *) aCallback {

self = [super init];

if (self) {

uploadDir = [NSString stringWithFormat: @"ftp://aServer.org/%i/", aTimeseriesID];
ftpUser = @"aUser";
ftpPass = @"aPass";

datasetDir = aDir;
files = filesArg;

bufferOffset = 0;
bufferLimit = 0;

index = 0;

callback = aCallback;
}

return self;
}

- (void) createDir {

uploadMode = UploadModeCreateDir;
NSURL *destinationDirURL = [NSURL URLWithString: uploadDir];

CFWriteStreamRef writeStreamRef = CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) destinationDirURL);
assert(writeStreamRef != NULL);

ftpStream = (__bridge_transfer NSOutputStream *) writeStreamRef;
[ftpStream setProperty: ftpUser forKey: (id)kCFStreamPropertyFTPUserName];
[ftpStream setProperty: ftpPass forKey: (id)kCFStreamPropertyFTPPassword];

ftpStream.delegate = self;
[ftpStream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
// open stream
[ftpStream open];

CFRelease(writeStreamRef);
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {

NSLog(@"aStream has an event: %i", eventCode);

switch (eventCode) {
// all cases handled properly
default:
// no event
NSLog(@"default mode; no event");
break;
}
}

编辑:添加了在类 UploadDatasetVC 中使用的创建代码:

FTPUploads *uploads = [[FTPUploads alloc] initWithTimeseriesID: timeseries_id 
fromDatasetDir: datasetDir
withFiles: files
andCallbackObject: self];
[uploads createDir];

最佳答案

在我看来,对您的 FTPUploads 对象的唯一引用是流中的 delegate 属性。这不会保留您的对象,因此如果没有其他对象引用该对象,该对象将被释放。弧。不会试图阻止这种情况。

您需要做的是让分配 FTPUploads 对象的代码保留对该对象的引用,直到它完成。

在您的 FTPUploads dealloc 方法中将 ftpStream.delegate 属性设置为 nil 也不是一个坏主意,因为这将防止对象崩溃被过早释放。

关于objective-c - 基于 ARC 的应用程序中的过早释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9150214/

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