Enlace débil: compruebe si existe una clase y use esa clase


Estoy tratando de crear una aplicación universal para iPhone, pero utiliza una clase definida solo en una versión más reciente del SDK. El framework existe en sistemas más antiguos, pero una clase definida en el framework no lo hace.

Sé que quiero usar algún tipo de enlace débil, pero cualquier documentación que pueda encontrar habla de comprobaciones de tiempo de ejecución para la existencia de la función - ¿cómo compruebo que existe una clase?

Author: Ben Mosher, 2010-06-17

2 answers

TLDR

Corriente:

  • Swift : if #available(iOS 9, *)
  • Obj-C, iOS : if (@available(iOS 11.0, *))
  • Obj-C, OS X : if (NSClassFromString(@"UIAlertController"))

Legado:

  • Swift (versiones anteriores a 2.0): if objc_getClass("UIAlertController")
  • Obj-C, iOS (versiones anteriores a 4.2): if (NSClassFromString(@"UIAlertController"))
  • Obj-C, iOS (versiones anteriores a 11.0): if ([UIAlertController class])

Swift 2 +

Aunque históricamente, se ha recomendado verificar las capacidades (o la existencia de clases) en lugar de versiones específicas del sistema operativo, esto no funciona bien en Swift 2.0 debido a la introducción de comprobación de disponibilidad.

Use esta manera en su lugar:

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(...)
}

Nota: Si en su lugar intenta usar objc_getClass(), obtendrá el siguiente error:

️ 'UIAlertController' solo está disponible en iOS 8.0 o posterior.


Versiones Anteriores de Swift

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

Tenga en cuenta que objc_getClass() es más fiable que NSClassFromString() o objc_lookUpClass().


Objective-C, iOS 4.2 +

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

Ver la respuesta de code007 para más detalles.


OS X o versiones anteriores de iOS

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

Uso NSClassFromString(). Si devuelve nil, la clase no existe, de lo contrario devolverá el objeto de clase que se puede usar.

Esta es la forma recomendada según Apple en esto documento:

[...] Su código probaría para el existencia de una clase [a] que utiliza NSClassFromString() que volverá un objeto de clase válido si [la] clase existe o no existe si no existe. Si el la clase existe, tu código puede usarla [...]

 155
Author: Senseful,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-11 06:51:02

Para proyectos nuevos que utilizan un SDK base de iOS 4.2 o posterior, existe este nuevo enfoque recomendado que consiste en usar el método de clase NSObject para verificar la disponibilidad de clases débilmente vinculadas en tiempo de ejecución. es decir,

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

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

Este mecanismo utiliza la macro NS_CLASS_AVAILABLE, que está disponible para la mayoría del framework en iOS (nota puede haber algún framework que aún no admita el NS_CLASS_AVAILABLE - revisa la nota de la versión de iOS para esto). También se puede necesitar una configuración adicional que se puede leer en el enlace de documentación de Apple proporcionado anteriormente, sin embargo, la ventaja de este método es que obtiene una comprobación de tipo estático.

 68
Author: code007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-29 12:51:24