“ ข้อผิดพลาดร้ายแรง: อาร์เรย์ไม่สามารถเชื่อมโยงกับ Objective-C ได้” - ทำไมคุณถึงลองใช้ Swift?


92

ฉันได้ประกาศโปรโตคอล Swift:

protocol Option {
    var name: String { get }
}

ฉันประกาศการใช้โปรโตคอลนี้หลายครั้ง - บางคลาสบางอัน

ฉันมีตัวควบคุมมุมมองพร้อมคุณสมบัติที่ประกาศดังนี้:

var options: [Option] = []

เมื่อฉันพยายามตั้งค่าคุณสมบัตินี้เป็นอาร์เรย์ของวัตถุที่ใช้Optionโปรโตคอลใน VC อื่นprepareForSegueฉันได้รับข้อผิดพลาดรันไทม์:

fatal error: array cannot be bridged from Objective-C

ทำไมถึงไม่ทำงาน คอมไพเลอร์มีข้อมูลทั้งหมดที่ต้องการและฉันไม่เข้าใจว่า Objective-C เกี่ยวข้องกับอะไรเลย - โปรเจ็กต์ของฉันมีเฉพาะไฟล์ Swift เท่านั้นและอาร์เรย์เหล่านี้ไม่ได้เข้ามาหรือออกจากเมธอดกรอบใด ๆ ที่จะ NSArrayเลี่ยงพวกเขาจะถูกเชื่อมไป


6
คุณพยายามที่จะ@objcนำหน้าโปรโตคอลของคุณหรือไม่? stackoverflow.com/a/28029568/377369
Fabio Poloni

1
ไม่ได้ผลหากการใช้โปรโตคอลใด ๆ เป็น enum: "ประเภทที่ไม่ใช่คลาส" Foo "ไม่สามารถเป็นไปตามโปรโตคอลคลาส" ตัวเลือก "
Robert Atkins

ทำไมต้องเป็นโปรโตคอลระดับ ฉันไม่ได้ส่งต่อไปยังเฟรมเวิร์ก Obj-C หรือสิ่งอื่นใดที่ต้องการให้ Swift Array เชื่อมโยงกับ NSArray
Robert Atkins

วิธีที่ Swift และ Objective-C ทำงานร่วมกันยังคงเป็นความลับสำหรับฉัน ฉันแค่ต้อง "ยอมรับ" หลาย ๆ อย่างซึ่งแค่ "ทำงาน" หรือ "ไม่ทำงาน"
Fabio Poloni

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

คำตอบ:


83

ฉันได้พบวิธีแก้ปัญหาแล้ว ค่อนข้าง ... ไม่น่าพอใจแต่ได้ผล ที่ฉันตั้งค่าอาร์เรย์บนตัวควบคุมมุมมองปลายทางที่ฉันทำ:

destinationViewController.options = options.map({$0 as Option})

คุณไม่สามารถส่งอาร์เรย์ทั้งหมดได้หรือไม่ options as [Option]
Kostiantyn Koval

ไม่ พยายามแล้ว (Xcode 6.3.1 (6D1002)) ไม่ทำงาน ฉันไม่จำเป็นต้องแคสต์ไม่ว่าในกรณีใด ๆ คอมไพเลอร์รู้ว่าฉันกำลังส่งผ่าน Array ของสิ่งต่างๆที่ใช้ Option
Robert Atkins

2
"อาร์เรย์ของสิ่งที่ใช้ตัวเลือก" อ่า แต่นั่นไม่เหมือนกับ Array of Option ซึ่งเป็นสิ่งที่คุณต้องการ ดูคำตอบของฉัน
แมต

1
มันใช้งานได้และใช่มันไม่น่าพอใจมาก ... ไม่จำเป็นต้องใช้ Swift น่าจะจัดการ htis ได้
Oscar Gomez

ฉันเห็นด้วย ... มันใช้ได้ดี แต่มันเป็นรหัสที่ไม่น่าพอใจมาก
Michael

22

คอมไพเลอร์รู้ว่าฉันกำลังส่งผ่าน Array ของสิ่งต่างๆที่ใช้ Option

คุณได้ปล่อยคำพูดที่เปิดเผยมากซึ่งชี้ให้เห็นที่มาของปัญหา "อาร์เรย์ของสิ่งที่ใช้ตัวเลือก" ไม่ใช่อาร์เรย์ของตัวเลือก

ปัญหาอยู่ที่ประเภทของการoptionsย้อนกลับ ณ จุดที่คุณสร้าง (ในprepareForSegue) คุณไม่ได้แสดงรหัสนั้น แต่ฉันพนันว่าคุณล้มเหลวในการส่ง / พิมพ์รหัสในตอนนั้น นั่นเป็นสาเหตุที่การมอบหมายงานล้มเหลว optionsอาจเป็นหลายสิ่งที่เกิดขึ้นจริงเพื่อนำ Option มาใช้ แต่นั่นยังไม่เพียงพอ ต้องพิมพ์เป็นอาร์เรย์ของตัวเลือก

ดังนั้นกลับเข้ามาในprepareForSegueรูปแบบของคุณoptionsเช่นนี้:

let options : [Option] = // ... whatever ...

ตอนนี้destinationViewController.optionsคุณจะสามารถที่จะกำหนดโดยตรงไปยัง

นี่เป็นกรณีทดสอบสั้น ๆ (ในสนามเด็กเล่นฉันเกลียดสนามเด็กเล่น แต่สามารถใช้ประโยชน์ได้):

protocol Option {
    var name : String {get}
}

class ViewController : UIViewController {
    var options : [Option] = []
}

enum Thing : Option {
    var name : String {
        get {
            return "hi"
        }
    }
    case Thing
}

let vc = ViewController()
let options : [Option] = [Thing.Thing]
vc.options = options // no problem

(ฉันยังทดสอบสิ่งนี้ในแอปจริงด้วยของจริงprepareForSegueและใช้งานได้ดี)


1
ผมคิดว่านี่คือการเสียมากเพราะคอมไพเลอร์ไม่ทราบที่รันไทม์ว่าสิ่งที่เป็นตัวเลือก และไม่ว่าในกรณีใดก็ตามดังที่ระบุไว้ในความคิดเห็นสำหรับคำตอบของฉันด้านล่างทั้งการแคสต์ ( viewController.options = things as [Option]) หรือการสร้างตัวแปร temp อย่างชัดเจนตาม[Option]ที่คุณแนะนำที่นี่ใช้งานได้จริง ในทั้งสองกรณีฉันได้รับข้อผิดพลาดรันไทม์
Robert Atkins

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

อาจจะ. แต่ฉันยังคงสับสนว่าสิ่งนี้เกี่ยวข้องกับอะไรกับ Objective-C ในตอนแรก (ข้อผิดพลาดรันไทม์ดั้งเดิม) ฉันไม่ได้ทำอะไรเลย (ที่ฉันเห็น) ซึ่งควรบังคับให้เชื่อมโยงกับ NSArray
Robert Atkins

2
ดูวิธีนี้ ฉันได้แสดงรหัสที่ใช้งานได้แล้ว คุณไม่ได้แสดงรหัสที่ใช้งานไม่ได้ฉันไม่สามารถทำให้ปัญหาของคุณเกิดซ้ำจากข้อมูลที่ให้มาได้ ช่วยฉันผลิตซ้ำ
แมตต์

1
@ CristiBăluță นั่นคือสิ่งที่คุณต้องค้นหาก่อนที่จะอ้างว่า "ปัญหานี้ยังไม่ได้รับการแก้ไข"
แมตต์

16

ฉันประสบปัญหาเดียวกันและแก้ไขโดยทำเครื่องหมายโปรโตคอลของฉันด้วย@objcในกรณีของคุณมันจะมีลักษณะเช่นนี้

@objc protocol Option {
    var name: String { get }
}

มีทางออกจากคำตอบนี้


1
เช่นเดียวกับในความคิดเห็นของคำถามเดิมสิ่งนี้จะใช้ไม่ได้หากผู้ใช้โปรโตคอลใด ๆ คือ Swift Enums ซึ่งในกรณีของฉันก็คือ
Robert Atkins

พิมพ์ obcj ควรเป็น objc
Alan Scarpa

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