Làm cách nào để chuyển đổi NSMutableArray sang NSArray?


Câu trả lời:


511
NSArray *array = [mutableArray copy];

Copylàm bản sao bất biến. Điều này khá hữu ích vì Apple có thể thực hiện các tối ưu hóa khác nhau. Ví dụ gửi copyđến một mảng bất biến chỉ giữ lại đối tượng và trả về self.

Nếu bạn không sử dụng bộ sưu tập rác hoặc ARC, hãy nhớ rằng -copyvẫn giữ đối tượng.


2
câu trả lời này rất hay, nhưng làm thế nào tôi có thể nói từ các tài liệu copytạo ra NSArray bình thường chứ không phải NSMutableArray?
Dan Rosenstark

22
@Yar: Bạn xem tài liệu của NSCopying Nó ghi ở đó: copyWithZone Bản sao được trả lại là bất biến nếu việc xem xét bất biến so với đối tượng có thể áp dụng đối với đối tượng nhận; mặt khác, bản chất chính xác của bản sao được xác định bởi lớp.
Georg Schölly

1
Rất gọn gàng - Tôi thích điều này hơn giải pháp của m5h. Cả hai ngắn gọn và hiệu quả hơn.
David Snabel-Caunt

1
Tôi đồng ý David, cập nhật phản hồi của tôi để chỉ ra phản hồi này.
hallski

2
@Brad: Điều đó chỉ có nghĩa là các lớp có cả hai triển khai có thể thay đổi và bất biến. Ví dụ NSArray& NSMutableArray, NSString& NSMutableString. Nhưng không phải ví dụ NSViewControllerluôn chứa trạng thái đột biến.
Georg Schölly

361

An NSMutableArraylà một lớp con của NSArrayvì vậy bạn sẽ không cần phải chuyển đổi nhưng nếu bạn muốn đảm bảo rằng mảng không thể được sửa đổi, bạn có thể tạo một NSArraytrong hai cách sau tùy thuộc vào việc bạn có muốn tự động phát hành hay không:

/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];

/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];

EDIT: Giải pháp được cung cấp bởi Georg Schölly là một cách tốt hơn để làm điều đó và sạch sẽ hơn rất nhiều, đặc biệt là bây giờ chúng tôi có ARC và thậm chí không phải gọi autorelease.


7
Tôi có thể làm (NSArray *) myMutableArray không?
Vojto

2
Có, vì NSMutableArray là một lớp con của NSArray hợp lệ.
hallski

4
Tuy nhiên, truyền tới (NSArray *) vẫn cho phép truyền sao lưu lên (NSMutable *). Không phải vậy sao?
sharvey

1
@sharvey: Vâng, đúng rồi. Bạn sẽ nhận được cảnh báo nếu bạn không sử dụng nhưng chỉ định siêu lớp cho lớp con trực tiếp. Thông thường, bạn muốn trả về một bản sao bất biến, bởi vì đó là cách duy nhất để chắc chắn, rằng mảng của bạn thực sự sẽ không được sửa đổi.
Georg Schölly

1
Trước đây được gọi là "Upcasting" (NSArray *) myMutableArray và nghịch đảo được gọi là "Downcasting"
Francisco Gutiérrez

113

Tôi thích cả hai giải pháp chính:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Hoặc là

NSArray *array = [mutableArray copy];

Sự khác biệt chính mà tôi thấy ở họ là cách họ cư xử khi mutableArray là con số không :

NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == @[] (empty array)

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil

Điều đó là sai. Mới kiểm tra. [bản sao mutableArray] cũng trả về một mảng trống.
durazno

@durazno Không sai. Kiểm tra lại bài kiểm tra của bạn Nếu [bản sao mutableArray] đang trả về một mảng trống, thì mutableArray phải là một mảng trống. Câu trả lời của tôi chỉ áp dụng khi mutableArray là nil.
Richard Venable

Mặc dù điều này là đúng, tôi cảm thấy như bạn đang thiếu một sự thật cơ bản hơn trong ví dụ của bạn. Vì bạn đã gán mutableArray là nil, [mutableArray copy]có thể được đơn giản hóa thành [nil copy]. Trong object-c, bất kỳ thông điệp nào được gửi đến nil sẽ luôn là nil. Điều quan trọng cần nhớ là phân biệt giữa "không có gì" và "một mảng không có gì trong đó".
mkirk

@mkirk Chúng ta đừng phân tâm câu hỏi: "Làm cách nào để chuyển đổi NSMutableArray thành NSArray?" Có 2 giải pháp chính và sự khác biệt chính giữa chúng là cách chúng hoạt động khi mảng có thể thay đổi là không.
Richard Venable

18

bạn thử mã này ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

NSArray *myArray = [myMutableArray copy];

Điều này làm gì mà những người khác không làm?
Ben Leggiero 15/03/2016

5

Mục tiêu-C

Dưới đây là cách để chuyển đổi NSMutableArray sang NSArray:

//oldArray is having NSMutableArray data-type.
//Using Init with Array method.
NSArray *newArray1 = [[NSArray alloc]initWithArray:oldArray];

//Make copy of array
NSArray *newArray2 = [oldArray copy];

//Make mutablecopy of array
NSArray *newArray3 = [oldArray mutableCopy];

//Directly stored NSMutableArray to NSArray.
NSArray *newArray4 = oldArray;

Nhanh

Trong Swift 3.0 có kiểu dữ liệu mới Array . Khai báo Array bằng lettừ khóa thì nó sẽ trở thành NSArray Và nếu khai báo sử dụng vartừ khóa thì nó sẽ trở thành NSMutableArray .

Mã mẫu:

let newArray = oldArray as Array

Phần Swift không hoàn toàn đúng. Xem ở đâyở đây để biết sự khác biệt giữa Arrays và NSArray/ NSMutableArrays bất biến . Chúng không giống nhau.
Bruno Ely

3

Trong mục tiêu-c:

NSArray *myArray = [myMutableArray copy];

Trong nhanh chóng:

 var arr = myMutableArray as NSArray

2
NSArray *array = mutableArray;

Đây [mutableArray copy]antipattern là khắp nơi trên mẫu mã. Dừng làm như vậy cho các mảng có thể thay đổi được tạm thời và được giải quyết ở cuối phạm vi hiện tại.

Không có cách nào thời gian chạy có thể tối ưu hóa việc sao chép lãng phí của một mảng có thể thay đổi sắp ra khỏi phạm vi, bị giải mã thành 0 và bị loại bỏ hoàn toàn.


Việc gán một biến NSMutableArraycho một NSArraybiến sẽ không làm thay đổi nó (đó là câu hỏi của OP). Việc phơi bày một giá trị như vậy (ví dụ như giá trị trả về hoặc là một tài sản) có thể dẫn đến các vấn đề rất khó gỡ lỗi nếu giá trị đó bị thay đổi bất ngờ. Điều này áp dụng cho cả đột biến bên trong và bên ngoài do giá trị đột biến được chia sẻ.
David Rönnqvist

Để thay đổi mảng đó, bạn phải [NSMutableArray mảngWithArray: ... hoặc một cái gì đó tương tự.
Anton Tropashko

Không cần thiết. Chỉ cần gán nó cho một NSMutableArraybiến là đủ. Vì đối tượng không bao giờ ngừng là một mảng có thể thay đổi, nên gọi các phương thức đột biến trên nó sẽ thành công và làm thay đổi dữ liệu chia sẻ. Mặt khác, mảng có thể thay đổi ban đầu đã được sao chép, thay đổi nó thành một mảng bất biến, sau đó được gán cho một NSMutableArraybiến và có các phương thức biến đổi được gọi trên đó, các cuộc gọi đó sẽ thất bại doesNotRespondToSelectorvì lỗi đã nhận được cuộc gọi phương thức đột biến thực tế bất biến và không đáp ứng với các phương pháp đó.
David Rönnqvist

ok, điều này có thể có một số công đức cho các nhà phát triển không chú ý đến trình biên dịch cảnh báo về các giả định chuyển đổi tyope
Anton Tropashko

1

Nếu bạn đang xây dựng một mảng thông qua khả năng biến đổi và sau đó muốn trả về một phiên bản không thay đổi, bạn có thể chỉ cần trả về mảng có thể thay đổi dưới dạng "NSArray" thông qua kế thừa.

- (NSArray *)arrayOfStrings {
    NSMutableArray *mutableArray = [NSMutableArray array];
    mutableArray[0] = @"foo";
    mutableArray[1] = @"bar";

    return mutableArray;
}

Nếu bạn "tin tưởng" người gọi để coi đối tượng trả về (về mặt kỹ thuật vẫn có thể thay đổi) như một NSArray bất biến, thì đây là một lựa chọn rẻ hơn [mutableArray copy].

Apple đồng tình:

Để xác định xem nó có thể thay đổi một đối tượng đã nhận hay không, người nhận tin nhắn phải dựa vào loại chính thức của giá trị trả về. Nếu nó nhận được, ví dụ, một đối tượng mảng được gõ là bất biến, thì nó không nên cố gắng biến đổi nó . Nó không phải là một thực tiễn lập trình có thể chấp nhận để xác định xem một đối tượng có thể thay đổi được hay không dựa trên tư cách thành viên của lớp.

Thực hành trên được thảo luận chi tiết hơn ở đây:

Cách thực hành tốt nhất: Trả về mutableArray.copy hoặc mutableArray nếu kiểu trả về là NSArray


0

Tôi đã tìm kiếm câu trả lời trong swift 3 và câu hỏi này đã được hiển thị như là kết quả đầu tiên trong tìm kiếm và tôi lấy cảm hứng từ câu trả lời từ đó vì vậy đây là mã 3 swift

let array: [String] = nsMutableArrayObject.copy() as! [String]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.