2009-08-03 28 views
7

Tôi khá mới với mục tiêu-c và cố gắng tạo một ứng dụng nhỏ cho iphone.
Tôi sắp hoàn thành bên cạnh lỗi nhỏ này ở đây. Trên thực tế, tôi đã tìm kiếm giờ với google để tìm một giải pháp thích hợp nhưng tiếc là tôi không thể tìm thấy một giải pháp hoạt động.
Tôi đang sử dụng hướng dẫn này ở đây để xây dựng một UITableView: UITableView Tutorial Thông báo lỗi đầy đủ trông như thế này:Mục tiêu-c "phương pháp đột biến được gửi đến đối tượng bất biến" lỗi

* Chấm dứt ứng dụng do ngoại lệ còn tự do 'NSInternalInconsistencyException', lý do: '* - [ NSCFArray insertObject: atIndex:]: phương pháp biến đổi gửi đến đối tượng bất biến'

Đây là dữ liệu điều khiển Tiêu đề: MyLinksDataController.h

@interface MyLinksDataController : NSObject { 

NSMutableArray *tableList; //<---important part 

} 

- (unsigned)countOfList; 
- (id)objectInListAtIndex:(unsigned)theIndex; 
- (void)addData:(NSString *)data; //<---important part 
- (void)removeDataAtIndex:(unsigned)theIndex; 

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; //<---important part 

..... 

Và Data Phương pháp điều khiển: MyLinksDataController.m

#import "MyLinksDataController.h" 

@implementation MyLinksDataController 

@synthesize tableList; 

- (id)init { 

    if (self = [super init]) { 

     NSLog(@"Initilizing DataController"); 
     //Instantiate list 
     NSMutableArray *localList = [[NSMutableArray alloc] init]; 
     self.tableList = [localList copy]; 
     [localList release]; 

     //Add initial Data 
     [self addData:@"AAAAAAAAAAAAAA"]; 
     [self addData:@"BBBBBBBBBBBBBB"]; 

    } 

    return self; 

} 

----------------------------- - ở bên trong mã nguồn ---------------------------------

- (void)addData:(NSString*)data; { 

    [tableList addObject:data]; //<---- here the app crashes 

} 

Tôi sẽ khá nhiều đánh giá cao sự giúp đỡ nào.

Cảm ơn bạn đã hỗ trợ trước.

Daniel

Trả lời

27

gửi các bản sao thông điệp tới một NSMutableArray - như trong các tuyên bố sau trong init - trả về một bản sao không thay đổi.

self.tableList = [localList copy]; 

tài liệu ca cao sử dụng từ bất biến để chỉ read-only, can't-được-thay đổi-sau-khởi tạo đối tượng. Do đó, lệnh gọi sau đến addObject: không thành công với thông báo lỗi.

Lưu ý cách câu lệnh gán ở trên không kích hoạt bất kỳ cảnh báo trình biên dịch nào. sao chép trả về mã số , phù hợp thoải mái - theo như trình biên dịch có liên quan - trong bảng liệt kê NSMutableArray *. Không có lỗi thời gian chạy ở đây, vì không có thông điệp nào được truyền đi xung quanh; một con trỏ NSArray chỉ được đặt trong một biến con trỏ NSMutableArray.

Để có bản sao có thể thay đổi, hãy sử dụng mutableCopy thay thế.

Lưu ý rằng cả hai sao chépmutableCopy tạo mảng mới và sao chép nội dung của bản gốc vào đó. Một thay đổi trong bản sao sẽ không được phản ánh trong bản gốc. Nếu bạn chỉ cần tham chiếu khác đến mảng ban đầu, hãy sử dụng giữ lại thay thế.

Bạn có thể tìm thêm chi tiết trong phần thảo luận của copyWithZone reference và trong NSMutableCopying protocol reference.

5

Bạn đang chạy vào, về cơ bản, các quy tắc quản lý bộ nhớ của Cocoa (specifically, these details). Nếu có một đối tượng có số immutable version và phiên bản có thể thay đổi thì gửi -copy đến một đối tượng sẽ trả về một đối tượng không thay đổi được.

Hãy bước qua phần có liên quan.

NSMutableArray *localList = [[NSMutableArray alloc] init]; 

Điều này tạo ra mảng trống mới, trống mà bạn sở hữu. Khỏe.

self.tableList = [localList copy]; 

này tạo ra một bất biến bản sao của mảng sản phẩm nào. Hơn nữa, bạn sở hữu bản sao mới được tạo này. Đó là hai đối tượng bạn sở hữu vào lúc này.

Điều này cũng gán đối tượng đã sao chép của bạn vào thuộc tính tableList. Hãy xem xét việc kê khai tài sản:

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; 

Khách sạn này được khai báo với copy attribute, vì vậy bất cứ khi nào một giá trị mới được gán cho nó, một phương pháp khác -copy được gửi đến nó. Tuy nhiên, bản sao thứ ba này không thuộc sở hữu của bạn — nó thuộc sở hữu của đối tượng.

[localList release]; 

Điều đó giải phóng mảng trống có thể thay đổi ban đầu. Tốt thôi, nhưng vẫn còn thứ bạn làm ở dòng thứ hai trôi nổi xung quanh, chưa được phát hành. Đó là một rò rỉ bộ nhớ.

Nếu bạn thực sự cần một bản sao có thể thay đổi, bạn muốn có phương thức -mutableCopy. (Tài liệu cho các phương thức này được tìm thấy dưới NSCopyingNSMutableCopying.) Tuy nhiên, bạn sẽ không bao giờ nhận được phiên bản biến thể của một cái gì đó vào thuộc tính với thuộc tính copy, vì nó sẽ gửi -copy cho bất kỳ thứ gì được gán. tài sản của bạn nên sử dụng retain thuộc tính thay vì thuộc tính copy, và mã để khởi tạo nó sẽ giống như thế này:

NSMutableArray *localList = [[NSMutableArray alloc] init]; 
self.tableList = localList; 
[localList release]; 

Hoặc, một phiên bản ngắn hơn:

self.tableList = [NSMutableArray array]; 

Không cần sao chép bất cứ điều gì trong tình huống này, bạn chỉ cần tạo ra một đối tượng mới.

+1

Nếu một tài sản bản sao được thực sự kêu gọi, sau đó thay thế một giữ lại tài sản sẽ là một giải pháp nghèo. Vì không có từ khóa mutablecopy, khai báo các tài sản như bản sao, nhưng viết accessor của riêng bạn thay vì sử dụng accessors tổng hợp. –

+0

Điểm tốt. Tôi cũng muốn nói rằng tôi hầu như không bao giờ thấy các đối tượng quảng cáo thuộc tính 'NSMutableArray'. Các purist trong tôi sẽ muốn nhìn thấy một setter tùy chỉnh lưu trữ một bản sao có thể thay đổi của đối tượng và một getter tùy chỉnh mà trả về một bản sao bất biến autoreleased. –

0

Hi thay vì mutableCopy tôi tin rằng "strong" cũng có thể được sử dụng để giải quyết vấn đề này. Tôi cũng gặp vấn đề tương tự trong mã của mình vì sử dụng "copy" thay vì "strong". Vì vậy, các dòng dưới đây:

@property (copy, nonatomic) NSMutableArray *computers; 

Nó nên là:

@property (strong, nonatomic) NSMutableArray *computers; 

Hy vọng nó sẽ được sự giúp đỡ to lớn cho người mới bắt đầu những sai lầm như tôi.

1

Nếu u đang gán danh sách cục bộ từ một đối tượng khác có thể không phải là Mutable trong trường hợp đó, nó có thể thông qua loại lỗi này.

Tôi hy vọng nó sẽ hữu ích.

self.tableList = [localList mutableCopy]; 
0

này sẽ giải quyết vấn đề:

NSMutableArray *localList = [[NSMutableArray alloc] init]; 
self.localList = [[NSMutableArray alloc]initWithArray:localList]; 
Các vấn đề liên quan