ฉันจะแปลง NSMutableArray เป็น NSArray ได้อย่างไร


381

ฉันจะแปลง NSMutableArray เป็น NSArray ได้อย่างไร ?


12
justNSArray *array = [mutableArray copy];
beryllium

1
NSArray *array = mutableArray;
vladof81

4
เบริลเลียม: ถูกต้องอย่างแน่นอน vladof81: ไม่แน่นอน
gnasher729

คำตอบ:


511
NSArray *array = [mutableArray copy];

Copyทำสำเนาไม่เปลี่ยนรูป สิ่งนี้มีประโยชน์มากเพราะ Apple สามารถเพิ่มประสิทธิภาพได้หลากหลาย ยกตัวอย่างเช่นการส่งเป็นแถวไม่เปลี่ยนรูปเท่านั้นยังคงมีวัตถุและผลตอบแทนcopyself

หากคุณไม่ได้ใช้การรวบรวมขยะหรือ ARC จำไว้ว่า-copyรักษาวัตถุ


2
คำตอบนี้ยอดเยี่ยม แต่ฉันจะบอกได้อย่างไรจากเอกสารที่copyสร้าง NSArray ปกติไม่ใช่ NSMutableArray
Dan Rosenstark

22
@Yar: คุณดูเอกสารของNSCopyingมันระบุว่า: copyWithZone คัดลอกกลับมาไม่เปลี่ยนรูปถ้าพิจารณา "ไม่เปลี่ยนรูปเทียบกับไม่แน่นอน" นำไปใช้กับวัตถุที่ได้รับ; มิฉะนั้นลักษณะที่แน่นอนของสำเนาจะถูกกำหนดโดยชั้นเรียน
Georg Schölly

1
เรียบร้อยมาก - ฉันชอบสิ่งนี้เพื่อแก้ปัญหาของ m5h ทั้งสั้นและมีประสิทธิภาพมากขึ้น
David Snabel-Caunt

1
ฉันยอมรับเดวิดอัปเดตคำตอบของฉันเพื่อชี้ไปยังคำตอบนี้
hallski

2
@Brad: นั่นหมายถึงคลาสที่มีการปรับใช้ที่ไม่แน่นอนและไม่เปลี่ยนรูป เช่นNSArray& NSMutableArray, NSString& NSMutableString. แต่ไม่ใช่ตัวอย่างNSViewControllerที่มีสถานะที่เปลี่ยนแปลงได้เสมอ
Georg Schölly

361

An NSMutableArrayเป็น subclass ของNSArrayดังนั้นคุณไม่จำเป็นต้องแปลงเสมอ แต่ถ้าคุณต้องการตรวจสอบให้แน่ใจว่าอาร์เรย์ไม่สามารถปรับเปลี่ยนได้คุณสามารถสร้างวิธีNSArrayใดวิธีหนึ่งเหล่านี้ขึ้นอยู่กับว่าคุณต้องการให้มันทำงานอัตโนมัติหรือไม่:

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

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

แก้ไข: วิธีการแก้ปัญหาโดย Georg Schöllyเป็นวิธีที่ดีกว่าในการทำและสะอาดกว่าโดยเฉพาะตอนนี้เรามี ARC และไม่ต้องโทรออกโดยอัตโนมัติ


7
ฉันสามารถทำ (NSArray *) myMutableArray ได้ไหม
Vojto

2
ใช่ NSMutableArray เป็น subclass ของ NSArray ที่ถูกต้อง
hallski

4
อย่างไรก็ตามการร่ายไปยัง (NSArray *) ยังคงอนุญาตให้ร่ายกลับขึ้นไป (NSMutable *) ไม่ใช่อย่างนั้นเหรอ?
แชร์

1
@sharvey: ใช่ถูกต้องแล้ว คุณจะได้รับคำเตือนหากคุณไม่ได้ส่ง แต่มอบหมาย Superclass ให้กับคลาสย่อยโดยตรง โดยปกติแล้วคุณต้องการคืนสำเนาที่ไม่เปลี่ยนรูปเพราะนั่นเป็นวิธีเดียวที่จะแน่ใจได้ว่าอาร์เรย์ของคุณจะไม่ได้รับการแก้ไข
Georg Schölly

1
เดิมชื่อ "Upcasting" (NSArray *) myMutableArray และสิ่งที่ตรงกันข้ามเรียกว่า "Downcasting"
Francisco Gutiérrez

113

ฉันชอบทั้งสองโซลูชั่นหลัก:

NSArray *array = [NSArray arrayWithArray:mutableArray];

หรือ

NSArray *array = [mutableArray copy];

ความแตกต่างหลักที่ฉันเห็นในพวกเขาคือวิธีการทำงานเมื่อ mutableArray เป็นศูนย์ :

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

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

นี่มันผิดมาก เพียงแค่ตรวจสอบ [mutableArray copy] จะส่งคืนอาร์เรย์ว่าง
durazno

@durazno มันไม่ผิด ตรวจสอบการทดสอบของคุณอีกครั้ง หาก [mutableArray copy] ส่งคืนอาร์เรย์ว่างเปล่าดังนั้น mutableArray จะต้องเป็นอาร์เรย์ว่างเปล่า คำตอบของฉันใช้เฉพาะเมื่อ mutableArray เป็นศูนย์
Richard Venable

แม้ว่านี่จะเป็นจริง แต่ฉันรู้สึกว่าคุณขาดความจริงพื้นฐานในแบบอย่างของคุณ เนื่องจากคุณได้มอบหมายให้ mutableArray เป็นศูนย์คุณ[mutableArray copy]สามารถทำให้ง่าย[nil copy]ขึ้น ในวัตถุประสงค์ข้อความใด ๆ ที่ส่งไปยังศูนย์จะเป็นศูนย์เสมอ สิ่งสำคัญคือต้องจดจำความแตกต่างระหว่าง "ไม่มี" และ "อาเรย์ที่ไม่มีอะไรอยู่ในนั้น"
mkirk

@mkirk อย่าหันเหความสนใจจากคำถามในมือ: "ฉันจะแปลง NSMutableArray เป็น NSArray ได้อย่างไร" มีวิธีแก้ไขปัญหาหลัก 2 แบบและความแตกต่างหลักระหว่างพวกเขาคือวิธีการทำงานเมื่ออาร์เรย์ที่ไม่แน่นอนเป็นศูนย์
Richard Venable

18

คุณลองใช้รหัสนี้ ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

และ

NSArray *myArray = [myMutableArray copy];

สิ่งนี้ทำอะไรที่คนอื่นไม่ทำ
Ben Leggiero

5

Objective-C

ด้านล่างเป็นวิธีการแปลง NSMutableArray เป็น 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;

รวดเร็ว

ในสวิฟท์ 3.0 มีใหม่ชนิดข้อมูลอาร์เรย์ อาร์เรย์ประกาศใช้letคำหลักแล้วมันจะกลายเป็นNSArrayและถ้าประกาศใช้varคำหลักแล้วก็กลายเป็นNSMutableArray

รหัสตัวอย่าง:

let newArray = oldArray as Array

ส่วน Swift ไม่ถูกต้องทั้งหมด ดูที่นี่และที่นี่เพื่อดูความแตกต่างระหว่างArrays ที่ไม่แน่นอน / ไม่เปลี่ยนรูปและNSArray/ NSMutableArrays พวกเขาไม่เหมือนกัน
Bruno Ely


2
NSArray *array = mutableArray;

[mutableArray copy]antipattern นี้เป็นรหัสตัวอย่าง หยุดการทำเช่นนั้นสำหรับอาร์เรย์ที่ไม่แน่นอนซึ่งเกิดขึ้นได้ซึ่งถูกส่งออกไปและถูกจัดสรรคืนเมื่อสิ้นสุดขอบเขตปัจจุบัน

ไม่มีวิธีที่ runtime สามารถปรับแต่งการคัดลอกอาเรย์ที่เปลี่ยนแปลงได้อย่างสิ้นเปลืองซึ่งกำลังจะออกจากขอบเขตลดลงเหลือ 0 และยกเลิกการจัดสรรให้ดี


การกำหนดNSMutableArrayให้กับNSArrayตัวแปรจะไม่แอบแฝงมัน (ซึ่งเป็นสิ่งที่คำถามของ OP เป็นเรื่องเกี่ยวกับ) การเปิดเผยค่าดังกล่าว (เช่นเป็นค่าส่งคืนหรือเป็นคุณสมบัติ) อาจส่งผลให้ยากต่อการดีบักปัญหาหากค่านั้นกลายพันธุ์โดยไม่คาดคิด สิ่งนี้ใช้กับการกลายพันธุ์ทั้งภายในและภายนอกเนื่องจากมีการแบ่งปันค่าที่ไม่แน่นอน
David Rönnqvist

ในการกลายพันธุ์อาเรย์นั้นคุณจะต้อง [NSMutableArray arrayWithArray: ... หรืออะไรทำนองนั้น
Anton Tropashko

ไม่จำเป็น. เพียงกำหนดให้NSMutableArrayตัวแปรก็เพียงพอแล้ว เนื่องจากวัตถุไม่เคยหยุดเป็นอาร์เรย์ที่ไม่แน่นอนการเรียกวิธีการกลายพันธุ์ในนั้นจะประสบความสำเร็จและกลายพันธุ์ข้อมูลที่ใช้ร่วมกัน หากในอีกทางหนึ่งอาเรย์ที่ไม่แน่นอนดั้งเดิมถูกคัดลอกเปลี่ยนเป็นอาเรย์ที่ไม่เปลี่ยนรูปและจากนั้นกำหนดให้กับNSMutableArrayตัวแปรและมีวิธีการกลายพันธุ์ที่เรียกว่ามันการเรียกเหล่านั้นจะล้มเหลวโดยมีdoesNotRespondToSelectorข้อผิดพลาดเนื่องจากวัตถุที่ได้รับการ ความจริงไม่เปลี่ยนรูปและไม่ตอบสนองต่อวิธีการเหล่านั้น
David Rönnqvist

ตกลงนี้อาจมีประโยชน์บางอย่างสำหรับนักพัฒนาที่ไม่ได้ฟังคำเตือนของคอมไพเลอร์เกี่ยวกับชุดการแปลงแบบ tyope
Anton Tropashko

1

หากคุณสร้างอาเรย์ด้วยความผันแปรแล้วต้องการคืนค่าเวอร์ชันที่ไม่เปลี่ยนรูปคุณสามารถส่งคืนอาเรย์ที่ไม่แน่นอนในรูปของ "NSArray" ผ่านการรับมรดก

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

    return mutableArray;
}

หากคุณ "ไว้วางใจ" โทรไปรักษา (ในทางเทคนิคยังคงไม่แน่นอน) วัตถุกลับมาเป็นไม่เปลี่ยนรูป NSArray [mutableArray copy]นี้เป็นตัวเลือกที่ราคาถูกกว่า

แอปเปิ้ลเห็นด้วย:

เพื่อตรวจสอบว่ามันสามารถเปลี่ยนวัตถุที่ได้รับผู้รับข้อความต้องขึ้นอยู่กับชนิดที่เป็นทางการของค่าตอบแทน หากได้รับตัวอย่างเช่นวัตถุอาร์เรย์พิมพ์เป็นไม่เปลี่ยนรูปมันไม่ควรพยายามที่จะเปลี่ยนแปลงมัน มันไม่ใช่วิธีการเขียนโปรแกรมที่ยอมรับได้เพื่อตรวจสอบว่าวัตถุนั้นเปลี่ยนแปลงได้หรือไม่ขึ้นอยู่กับความเป็นสมาชิกระดับของมัน

การปฏิบัติข้างต้นจะกล่าวถึงในรายละเอียดเพิ่มเติมที่นี่:

วิธีปฏิบัติที่ดีที่สุด: ส่งคืน mutableArray.copy หรือ mutableArray หากประเภทส่งคืนเป็น NSArray


0

ฉันค้นหาคำตอบใน swift 3 และคำถามนี้แสดงให้เห็นว่าเป็นผลลัพธ์ครั้งแรกในการค้นหาและฉันได้รับแรงบันดาลใจจากคำตอบดังนั้นนี่คือรหัส swift 3

let array: [String] = nsMutableArrayObject.copy() as! [String]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.