คอลเล็กชันที่ไม่เปลี่ยนรูป / เปลี่ยนรูปได้ใน Swift


88

ฉันอ้างถึงคู่มือการเขียนโปรแกรม Swift ของ Apple เพื่อทำความเข้าใจการสร้างวัตถุที่เปลี่ยนแปลงไม่ได้ / ไม่เปลี่ยนรูป (Array, Dictionary, Sets, Data) ในภาษา Swift แต่ฉันไม่เข้าใจวิธีสร้างคอลเล็กชันที่ไม่เปลี่ยนรูปใน Swift

ฉันต้องการดูสิ่งที่เทียบเท่าใน Swift สำหรับสิ่งต่อไปนี้ใน Objective-C

อาร์เรย์ที่ไม่เปลี่ยนรูป

NSArray *imArray = [[NSArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];

อาร์เรย์ที่ไม่แน่นอน

NSMutableArray *mArray = [[NSMutableArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];
[mArray addObject:@"Fourth"];

พจนานุกรมไม่เปลี่ยนรูป

NSDictionary *imDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];

พจนานุกรมไม่แน่นอน

NSMutableDictionary *mDictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];
[mDictionary setObject:@"Value3" forKey:@"Key3"];

คำตอบ:


115

อาร์เรย์

สร้างอาร์เรย์ที่ไม่เปลี่ยนรูป

วิธีแรก:

let array = NSArray(array: ["First","Second","Third"])

วิธีที่สอง:

let array = ["First","Second","Third"]

สร้างอาร์เรย์ที่ไม่แน่นอน

var array = ["First","Second","Third"]

ผนวกวัตถุเข้ากับอาร์เรย์

array.append("Forth")


พจนานุกรม

สร้างพจนานุกรมที่ไม่เปลี่ยนรูป

let dictionary = ["Item 1": "description", "Item 2": "description"]

สร้างพจนานุกรมที่ไม่แน่นอน

var dictionary = ["Item 1": "description", "Item 2": "description"]

เพิ่มคู่ใหม่ในพจนานุกรม

dictionary["Item 3"] = "description"

ข้อมูลเพิ่มเติมเกี่ยวกับ Apple Developer


12
อาร์เรย์ "ความยาวคงที่" จะแม่นยำกว่า มันไม่เปลี่ยนรูป
Sulthan

1
ไม่เปลี่ยนรูปไม่เปลี่ยนรูปDictionaryอย่างแท้จริง (ตรงข้ามกับ Array)
Bryan Chen

@BryanChen โอ้ .. ขอบคุณ!
nicael

@BryanChen varอ้อฉันลืมที่จะลบ
nicael

2
ได้. ข้อมูลเพิ่มเติมเกี่ยวกับการยกเลิกการเปลี่ยนรูปของอาร์เรย์ในคำถามนี้และคำตอบของมัน
Matt Gibson

31

Swift ไม่มีการลดลงในการทดแทนNSArrayหรือคลาสคอลเลกชันอื่น ๆ ใน Objective-C

มีคลาสอาร์เรย์และพจนานุกรม แต่ควรสังเกตว่าเป็นประเภท "ค่า" เมื่อเทียบกับ NSArray และ NSDictionary ซึ่งเป็นประเภท "วัตถุ"

ความแตกต่างนั้นละเอียดอ่อน แต่สำคัญมากในการหลีกเลี่ยงจุดบกพร่องของขอบ

อย่างรวดเร็วคุณสร้างอาร์เรย์ "ไม่เปลี่ยนรูป" ด้วย:

let hello = ["a", "b", "c"]

และอาร์เรย์ "เปลี่ยนแปลงได้" ด้วย:

var hello = ["a", "b", "c"]

อาร์เรย์ที่เปลี่ยนแปลงได้สามารถแก้ไขได้เช่นเดียวกับNSMutableArray:

var myArray = ["a", "b", "c"]

myArray.append("d") // ["a", "b", "c", "d"]

อย่างไรก็ตามคุณไม่สามารถส่งอาร์เรย์ที่เปลี่ยนแปลงได้ไปยังฟังก์ชัน:

var myArray = ["a", "b", "c"]

func addToArray(myArray: [String]) {
  myArray.append("d") // compile error
}

แต่รหัสด้านบนใช้งานได้กับ NSMutableArray:

var myArray = ["a", "b", "c"] as NSMutableArray

func addToArray(myArray: NSMutableArray) {
  myArray.addObject("d")
}

addToArray(myArray)

myArray // ["a", "b", "c", "d"]

คุณสามารถบรรลุNSMutableArrayพฤติกรรมโดยใช้inoutพารามิเตอร์วิธีการ:

var myArray = ["a", "b", "c"]

func addToArray(inout myArray: [String]) {
  myArray.append("d")
}

addToArray(&myArray)

myArray // ["a", "b", "c", "d"]

เขียนคำตอบนี้อีกครั้งเมื่อ 2015-08-10 เพื่อสะท้อนพฤติกรรม Swift ในปัจจุบัน


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

ตามที่ฉันได้กล่าวไว้ในคำตอบของฉันการถูกส่งผ่านเนื่องจากค่ามีความเกี่ยวข้องกับความผันแปร / ไม่เปลี่ยนรูปเนื่องจากครั้งเดียวที่คุณสนใจคือเมื่อส่งอาร์เรย์ไปยังรหัสอื่น (ซึ่งอาจแก้ไขได้)
Abhi Beckert

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

6

มีเพียงหนึ่งArrayและDictionaryประเภทเดียวใน Swift ความไม่แน่นอนขึ้นอยู่กับว่าคุณสร้างมันอย่างไร:

var mutableArray = [1,2,3]
let immutableArray = [1,2,3]

กล่าวคือถ้าคุณสร้างการกำหนดให้กับตัวแปรมันจะไม่แน่นอนในขณะที่คุณสร้างการกำหนดให้เป็นค่าคงที่จะไม่เป็นเช่นนั้น

คำเตือน:อาร์เรย์ที่ไม่เปลี่ยนรูปไม่เปลี่ยนรูปทั้งหมด! คุณยังคงสามารถเปลี่ยนเนื้อหาได้ไม่ใช่แค่ความยาวโดยรวมเท่านั้น!


1
FYI: พฤติกรรมของอาร์เรย์กำลังเปลี่ยนแปลงในเบต้าที่กำลังจะมาถึง ฉันคิดว่าทุกคนต่างก็มีเรื่องนั้น
russbishop

@xenadu ที่มา? ETA ในรุ่นเบต้านั้นหรือไม่
ไฟล์อนาล็อก

ขออภัยไม่มีแหล่งที่มา มันมาจากการสนทนากับสมาชิกทีมคอมไพเลอร์คนหนึ่ง นอกจากนี้เขายังกล่าวอีกว่า Beta 2 นั้นเป็นเพียงการตรวจสอบในการแก้ไขข้อบกพร่องแล้วและไม่มีอะไรเกี่ยวข้องกับข้อเสนอแนะหลัง WWDC
russbishop

5

เพียงแค่ประกาศวัตถุหรือตัวแปร (ใด ๆ ) ของคุณด้วย

'let' key word -> for "constan/Immutable" array, dictionary, variable, object..etc.

และ

'var' key word -> for "Mutable" array, dictionary, variable, object..etc. 

สำหรับข้อมูลเพิ่มเติมอย่างลึกซึ้ง

“ ใช้letเพื่อสร้างค่าคงที่และvarเพื่อสร้างตัวแปร ไม่จำเป็นต้องทราบค่าของค่าคงที่ในเวลาคอมไพล์ แต่คุณต้องกำหนดค่าหนึ่งครั้ง ซึ่งหมายความว่าคุณสามารถใช้ค่าคงที่เพื่อตั้งชื่อค่าที่คุณกำหนดเพียงครั้งเดียว แต่ใช้ได้หลายที่ "

var myVariable = 42
myVariable = 50
let myConstant = 42

อ่าน“ ภาษาการเขียนโปรแกรม Swift”


ในกรณีของ Array สิ่งนี้ไม่ได้ผลตามที่คาดไว้ stackoverflow.com/a/24319712/623710
macshome

3

หากคุณต้องการใช้งานArray(Swift) เช่นเดียวกับNSArrayคุณสามารถใช้ฟังก์ชันบริดจ์แบบธรรมดาได้ ตัวอย่าง:

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

มันทำงานเหมือนกันสำหรับlet.


0

จากเอกสารของ Apple:

ความไม่แน่นอนของคอลเลกชัน

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

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID105

การใช้คอลเลกชันอื่น ๆ ที่ไม่เปลี่ยนรูป / เปลี่ยนรูปได้ขึ้นอยู่กับว่าเหตุใดคุณจึงต้องการให้คอลเลกชันเหล่านั้นไม่เปลี่ยนแปลง / ไม่เปลี่ยนรูป คอลเล็กชันคือประเภทค่าใน Swift ซึ่งหมายความว่าเนื้อหาจะถูกคัดลอกเมื่อถูกกำหนดให้กับค่าอื่นหรือส่งต่อไปยังฟังก์ชัน / วิธีการอื่น ดังนั้นคุณไม่จำเป็นต้องกังวลว่าฟังก์ชันวิธีการรับอาจเปลี่ยนอาร์เรย์เดิมหรือไม่ ดังนั้นคุณไม่จำเป็นต้องตรวจสอบให้แน่ใจว่าได้ส่งคืนคอลเล็กชันที่ไม่เปลี่ยนรูปเช่นหากชั้นเรียนของคุณมีคอลเล็กชันที่ไม่แน่นอน


0

[ไม่สามารถแก้ไขได้และไม่เปลี่ยนรูป]

อาร์เรย์ของ Swift สามารถปิดเสียงได้

[let vs var ค่าเทียบกับประเภทอ้างอิง]

คอลเลกชันที่ไม่เปลี่ยนรูป[เกี่ยวกับ] - เป็นโครงสร้างคอลเลกชันที่ไม่สามารถเปลี่ยนแปลงได้ หมายความว่าคุณไม่สามารถเพิ่มลบแก้ไขหลังจากสร้างได้

let + struct(เช่นArray, Set, Dictionary) จะเหมาะที่จะไม่เปลี่ยนรูป

มีบางคลาส (เช่นNSArray) ที่ไม่มีอินเทอร์เฟซสำหรับเปลี่ยนสถานะภายใน

แต่

class A {
    var value = "a"
}

func testMutability() {
    //given
    let a = A()
    
    let immutableArr1 = NSArray(array: [a])
    let immutableArr2 = [a]
    
    //when
    a.value = "aa"
    
    //then
    XCTAssertEqual("aa", (immutableArr1[0] as! A).value)
    XCTAssertEqual("aa", immutableArr2[0].value)
}   

มันค่อนข้างจะเป็นunmodifiableอาร์เรย์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.