การเชื่อมโยงที่อ่อนแอ - ตรวจสอบว่ามีคลาสอยู่หรือไม่และใช้คลาสนั้น


87

ฉันกำลังพยายามสร้างแอปสำหรับ iPhone แบบสากล แต่ใช้คลาสที่กำหนดไว้ใน SDK เวอร์ชันที่ใหม่กว่าเท่านั้น เฟรมเวิร์กมีอยู่ในระบบเก่า แต่คลาสที่กำหนดไว้ในเฟรมเวิร์กไม่มี

ฉันรู้ว่าฉันต้องการใช้การเชื่อมโยงที่อ่อนแอ แต่เอกสารใด ๆ ที่ฉันสามารถค้นหาการพูดคุยเกี่ยวกับการตรวจสอบรันไทม์สำหรับการมีอยู่ของฟังก์ชัน - ฉันจะตรวจสอบได้อย่างไรว่ามีคลาสอยู่


ชั้นคืออะไร? อาจมีวิธีแก้ปัญหาอื่น ๆ
Marcelo Cantos

คำตอบ:


164

TLDR

ปัจจุบัน:

  • รวดเร็ว :if #available(iOS 9, *)
  • Obj-C, iOS :if (@available(iOS 11.0, *))
  • Obj-C, OS X :if (NSClassFromString(@"UIAlertController"))

มรดก:

  • Swift (เวอร์ชันก่อน 2.0) :if objc_getClass("UIAlertController")
  • Obj-C, iOS (เวอร์ชันก่อนหน้า 4.2) :if (NSClassFromString(@"UIAlertController"))
  • Obj-C, iOS (เวอร์ชันก่อน 11.0) :if ([UIAlertController class])

Swift 2+

แม้ว่าในอดีตจะได้รับการแนะนำให้ตรวจสอบความสามารถ (หรือการมีอยู่ของคลาส) มากกว่าเวอร์ชันของระบบปฏิบัติการที่เฉพาะเจาะจง แต่สิ่งนี้ทำงานได้ไม่ดีใน Swift 2.0 เนื่องจากมีการแนะนำการตรวจสอบความพร้อมใช้งานการตรวจสอบความพร้อมใช้งาน

ใช้วิธีนี้แทน:

if #available(iOS 9, *) {
    // You can use UIStackView here with no errors
    let stackView = UIStackView(...)
} else {
    // Attempting to use UIStackView here will cause a compiler error
    let tableView = UITableView(...)
}

หมายเหตุ:หากคุณพยายามใช้แทนคุณobjc_getClass()จะได้รับข้อผิดพลาดต่อไปนี้:

⛔️ 'UIAlertController' พร้อมใช้งานบน iOS 8.0 หรือใหม่กว่าเท่านั้น


Swift เวอร์ชันก่อนหน้า

if objc_getClass("UIAlertController") != nil {
    let alert = UIAlertController(...)
} else {
    let alert = UIAlertView(...)
}

ทราบว่าobjc_getClass() มีความน่าเชื่อถือมากกว่าNSClassFromString()objc_lookUpClass()หรือ


Objective-C, iOS 4.2+

if ([SomeClass class]) {
    // class exists
    SomeClass *instance = [[SomeClass alloc] init];
} else {
    // class doesn't exist
}

ดูคำตอบ code007 สำหรับรายละเอียดเพิ่มเติม


OS X หรือ iOS เวอร์ชันก่อนหน้า

Class klass = NSClassFromString(@"SomeClass");
if (klass) {
    // class exists
    id instance = [[klass alloc] init];
} else {
    // class doesn't exist
}

ใช้NSClassFromString(). ถ้าส่งคืนnilคลาสจะไม่มีอยู่มิฉะนั้นจะส่งคืนคลาสออบเจ็กต์ที่สามารถใช้ได้

นี่เป็นวิธีที่แนะนำตาม Apple ในเอกสารนี้ :

[... ] รหัสของคุณจะทดสอบการมีอยู่ของคลาส [a] ที่ใช้ NSClassFromString()ซึ่งจะส่งคืนอ็อบเจ็กต์คลาสที่ถูกต้องถ้าคลาส [the] มีอยู่หรือไม่มีถ้ามันไม่มี หากมีคลาสอยู่รหัสของคุณสามารถใช้งานได้ [... ]


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

2
สะดุดตานี้เป็นเพียงวิธีการใน OSX แต่ไม่ใช่วิธีที่ "ดีที่สุด" บน iOS (เวอร์ชัน 4.2 ขึ้นไป) แต่มันจะทำงาน ดูคำตอบของ code007 สำหรับ iOS โดยเฉพาะ
Ben Mosher

จะเกิดอะไรขึ้นถ้าชั้นเรียนของฉันไม่ใช่คลาสจริง แต่เป็นโครงสร้าง C?
Nathan H

สวิฟท์ 4.1 canImportจะมาพร้อมกับการตรวจสอบใหม่ ข้อเสนอ
จัดส่งหลัก

69

สำหรับโปรเจ็กต์ใหม่ที่ใช้ SDK พื้นฐานของ iOS 4.2 หรือใหม่กว่ามีแนวทางใหม่ที่แนะนำนี้คือการใช้วิธีการคลาส NSObject เพื่อตรวจสอบความพร้อมใช้งานของคลาสที่เชื่อมโยงอย่างอ่อนในขณะรันไทม์ กล่าวคือ

if ([UIPrintInteractionController class]) {
    // Create an instance of the class and use it.
} else {
    // Alternate code path to follow when the
    // class is not available.
}

แหล่งข้อมูล: https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW3

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


3
เกมช้าไปหน่อย แต่ฉันเพิ่งพบปัญหานี้เมื่อพยายามสร้างโค้ดที่มีอยู่UIAlertControllerในขณะที่ยังคงรองรับ iOS 7. คำตอบของ code007 นั้นถูกต้อง แต่การกำหนดค่าเพิ่มเติมที่จำเป็นคือการเชื่อมโยงอย่างอ่อนแอ (ตั้งค่าจากRequiredเป็นOptional) UIKit ในโครงการของคุณ (อย่างน้อยสำหรับสถานการณ์นี้)
Evan R
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.