init coder aDecoder คืออะไร?


122

ฉันกำลังเรียนรู้การพัฒนา iOS จากหลักสูตรออนไลน์และทุกครั้งที่สร้างมุมมองแบบกำหนดเอง (เซลล์มุมมองตารางที่กำหนดเองเซลล์มุมมองคอลเลกชัน ฯลฯ ) ผู้สอนจะใช้เครื่องมือเริ่มต้นนี้เสมอ:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

ทำไมฉันต้องเรียกสิ่งนี้เสมอ? มันทำอะไร? ฉันสามารถใส่คุณสมบัติภายใน init ได้หรือไม่


5
คำตอบนี้จะช่วยให้คุณstackoverflow.com/questions/24036393/…ขอบคุณ
Seungyoun Yi

2
หากคุณซับคลาสอ็อบเจ็กต์ที่ใช้งานNSCodingคุณจะต้องใช้ initialiser นี้เนื่องจากเป็นคลาสที่NSCodingต้องการ อย่างน้อยคุณต้องเรียกใช้ superclass init method หากNSCoderมีคุณสมบัติที่เข้ารหัสสำหรับชั้นเรียนของคุณคุณสามารถใช้วิธีนี้เพื่อกู้คืนสิ่งเหล่านั้น
Paulw11

1
นอกจากนี้ฉันขอแนะนำให้คุณอ่านหัวข้อเกี่ยวกับการเริ่มต้นวัตถุในหนังสือ Swift อย่างเป็นทางการของ Apple
Nicolas Miari

คำตอบ:


121

ฉันจะเริ่มคำตอบจากทิศทางตรงกันข้าม: ถ้าคุณต้องการบันทึกสถานะของมุมมองของคุณลงในดิสก์ล่ะ? นี้เป็นที่รู้จักกันเป็นอันดับ การย้อนกลับคือdeserialization - การกู้คืนสถานะของวัตถุจากดิสก์

NSCodingโปรโตคอลสองกำหนดวิธีการที่จะเป็นอันดับและ deserialize วัตถุ:

encodeWithCoder(_ aCoder: NSCoder) {
    // Serialize your object here
}

init(coder aDecoder: NSCoder) {
    // Deserialize your object here
}

เหตุใดจึงจำเป็นต้องมีในคลาสที่กำหนดเองของคุณ คำตอบคือ Interface Builder เมื่อคุณลากออบเจ็กต์ไปยังสตอรีบอร์ดและกำหนดค่าอินเทอร์เฟซ Builder จะทำให้สถานะของออบเจ็กต์นั้นเป็นซีเรียลลงในดิสก์จากนั้นจึงยกเลิกการกำหนดค่าเริ่มต้นเมื่อสตอรีบอร์ดปรากฏบนหน้าจอ คุณต้องบอก Interface Builder ว่าจะทำอย่างไร อย่างน้อยที่สุดหากคุณไม่ได้เพิ่มคุณสมบัติใหม่ ๆ ให้กับคลาสย่อยของคุณคุณสามารถขอให้ซูเปอร์คลาสทำการบรรจุและแกะกล่องให้คุณได้ด้วยเหตุนี้การsuper.init(coder: aDecoder)โทร หากคลาสย่อยของคุณมีความซับซ้อนมากขึ้นคุณจะต้องเพิ่มรหัสซีเรียลไลเซชั่นและรหัสการแยกย่อยของคุณเองสำหรับคลาสย่อย

สิ่งนี้ตรงกันข้ามกับแนวทางของ Visual Studio ซึ่งก็คือการเขียนโค้ดลงในไฟล์ที่ซ่อนอยู่เพื่อสร้างวัตถุในขณะทำงาน


ทำไมไม่ใส่ทุกอย่างไว้ใน AwakenFromNib แล้วลืมใช้init(coder aCoder : NSCoder)ล่ะ?
น้ำผึ้ง

@Honey - "บางครั้งคุณก็ทำไม่ได้" โดยทั่วไปคุณสามารถทำได้ แต่ไม่เสมอไป
Fattie

@ แฟตตี้คือรายละเอียดของการทำไม่ซับซ้อนเกินไปหรือไม่จำเป็นต้องรู้? ถ้าคุณไม่คิดจะอธิบาย?
น้ำผึ้ง

9
@Honey หากคุณต้องการกำหนดค่าวัตถุของคุณใน Interface Builder awakeFromNibจะไม่ทำงาน awakeFromNibถูกเรียกในเวลาทำงาน สิ่งที่คุณทำใน Interface Builder เป็นช่วงเวลาในการออกแบบ ในการดำเนินการสิ่งที่คุณทำในเวลาออกแบบกับเวลาทำงานคือencodeWithCoder(ประหยัด) และinit(coder:)(กำลังโหลด)
รหัสแตกต่างกัน

3
@Honey ถ้าคุณไม่ได้ใช้ Interface Builder เพื่อกำหนดค่าคลาสที่คุณกำหนดเอง (เช่นทำโดยใช้รหัสทางโปรแกรม) คุณสามารถทำได้ในawakeFromNibหรือinitWIthFrame
Code Different

28

ข้อกำหนดในการใช้งาน initializer นั้นเป็นผลมาจากสองสิ่ง:

  1. หลักการทดแทน Liskov ถ้า S เป็นคลาสย่อยของ T (เช่นMyViewControllerเป็นคลาสย่อยของViewController) ดังนั้นอ็อบเจ็กต์ S (อินสแตนซ์ของMyViewController) จะต้องสามารถถูกแทนที่ได้ในที่ที่ViewControllerคาดว่าอ็อบเจ็กต์ T (อินสแตนซ์ของ)

  2. Initializers จะไม่สืบทอดใน Swift หากตัวเริ่มต้นใด ๆ ถูกกำหนดไว้อย่างชัดเจนในคลาสย่อย หากมีการระบุตัวเริ่มต้นหนึ่งรายการอย่างชัดเจนจะต้องมีการระบุตัวอื่นทั้งหมดอย่างชัดเจน (ซึ่งสามารถโทรได้super.init(...)) ดูคำถามนี้เพื่อดูเหตุผล มันอยู่ใน Java แต่ยังใช้ได้

เมื่อถึงจุดที่ 1 ทุกอย่างที่ต้นฉบับViewControllerสามารถทำได้MyViewControllerคลาสย่อยควรจะทำได้ NSCoderสิ่งหนึ่งที่ดังกล่าวคือการสามารถที่จะเริ่มต้นจากที่กำหนด เมื่อถึงจุดที่ 2 MyViewControllerคลาสย่อยของคุณจะไม่สืบทอดความสามารถนี้โดยอัตโนมัติ ดังนั้นคุณต้องจัดหา initializer ที่ตรงตามข้อกำหนดนี้ด้วยตนเอง ในกรณีนี้คุณเพียงแค่ต้องมอบหมายให้กับซูเปอร์คลาสเพื่อให้มันทำในสิ่งที่มักจะทำ


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

3
ที่จริงแล้ว initializers ได้รับการสืบทอดมาใน Swift เนื่องจากคุณไม่ได้ให้การใช้งาน initializer ของคุณเองในคลาสย่อยของคุณ หากคุณสมบัติที่ไม่ได้รับการกำหนดใหม่ของคุณมีค่าเริ่มต้นคุณสามารถหลีกเลี่ยงการเขียนตัวเริ่มต้นใด ๆ ในคลาสย่อยของคุณและเพียงแค่สืบทอดค่าเริ่มต้นของคลาสพิเศษทั้งหมดของคุณ ดูที่นี่
TheBaj
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.