Tôi gặp sự cố có vẻ như là bản phát hành sớm của đối tượng được sử dụng trong ứng dụng dựa trên ARC. Tôi đang cố tạo thư mục trên máy chủ FTP. Các phần mã có liên quan dưới đây; tôi sẽ mô tả vấn đề trước.dealloc sớm trong ứng dụng dựa trên ARC
vấn đề với mã là, kết xuất debug trong phương pháp
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
không bao giờ được gọi.
Thay vào đó, tôi chỉ gặp lỗi _EXC_BAD_ACCESS_. Trong khi gỡ lỗi tôi phát hiện ra hai điều:
lỗi chỉ xuất hiện nếu dòng mã sau đây (createDir phương pháp) được thực hiện:
[ftpStream open];
nếu thông điệp rằng không được gửi , phần còn lại của mã không thực sự hợp lý - nhưng nó không bị hỏng ...
Tôi theo dõi các EXC_BAD_ACCESS xuống với NSZombieEnabled: Với đối tượng zombie kích hoạt, GDB tạo ra các thông tin gỡ lỗi sau:
*** -[FTPUploads respondsToSelector:]: message sent to deallocated instance 0x9166590
Địa chỉ gọi 0x9166590 là địa chỉ của FTPUploads tôi phản đối. Có vẻ như các đại biểu luồng được deallocated trước khi nó có thể xử lý tin nhắn.
Tại sao hệ thống lại phân phối một đối tượng đang sử dụng? Làm thế nào tôi có thể ngăn chặn nó được deallocated sớm?
mã:
FTPUploads.h trích đoạn:
#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 trích
#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;
}
}
EDIT: thêm mã tạo được sử dụng trong lớp UploadDatasetVC:
FTPUploads *uploads = [[FTPUploads alloc] initWithTimeseriesID: timeseries_id
fromDatasetDir: datasetDir
withFiles: files
andCallbackObject: self];
[uploads createDir];
Các đối tượng thường không giữ lại (hoặc trong trường hợp vòng cung, giữ lại các tham chiếu mạnh mẽ cho) các đại biểu của họ. Dường như với tôi như vấn đề sẽ được với mã mà tạo ra đối tượng FtpUploads của bạn và những gì nó sau đó không với nó –
Tôi đang thêm mã đó trong một đoạn trích khác của câu hỏi. cũng thấy bình luận của tôi về câu trả lời đầu tiên. –
Điều gì xảy ra sau đó? Nếu tải lên chỉ là một biến địa phương khi nó đi ra khỏi phạm vi ARC sẽ zap nó –