약한 연결-클래스가 있는지 확인하고 해당 클래스를 사용합니다.


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 이상

역사적으로 특정 OS 버전이 아닌 기능 (또는 클래스 존재)을 확인하는 것이 권장되었지만 가용성 확인 이 도입 되었기 때문에 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(...)
}

Note: If you instead attempt to use objc_getClass(), you will get the following error:

⛔️ 'UIAlertController' is only available on iOS 8.0 or newer.


Previous versions of Swift

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

Note that objc_getClass() is more reliable than NSClassFromString() or objc_lookUpClass().


Objective-C, iOS 4.2+

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

See code007's answer for more details.


OS X or previous versions of iOS

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

Use NSClassFromString(). If it returns nil, the class doesn't exist, otherwise it will return the class object which can be used.

This is the recommended way according to Apple in this document:

[...] Your code would test for the existence of [a] class using NSClassFromString() which will return a valid class object if [the] class exists or nil if it doesnʼt. If the class does exist, your code can use it [...]


Thanks. Just to complete the answer for others, once you have detected the class you create it using the Class instance returned by NSClassFromString (assign it to id) and invoke selectors on that instance.
psychotik

2
Notably, this is the only way on OSX, but not the "best" way on iOS (4.2+), though it will work. See code007's answer for iOS specifically.
Ben Mosher

What if my class is not a real class but rather a C struct?
Nathan H

Swift 4.1 is coming with new check canImport. Proposal
dispatchMain

69

For new projects that uses a base SDK of iOS 4.2 or later, there is this new recommended approach which is to use the NSObject class method to check the availability of weakly linked classes at run time. i.e.

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

source: https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//apple_ref/doc/uid/20002000-SW3

This mechanism uses the NS_CLASS_AVAILABLE macro, which is available for most framework in iOS (note there may be some framework that do not yet support the NS_CLASS_AVAILABLE - check the iOS release note for this). Extra setting configuration may also be needed that can be read in the Apple's documentation link provided above, however, the advantage of this method is that you get static type checking.


3
A little late to the game, but I just ran into this issue when trying to build code that contained UIAlertController while still supporting iOS 7. code007's answer is correct, but the extra configuration needed is to weakly link (set from Required to Optional) UIKit in your project (for this situation, at least).
Evan R
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.