NSClassFromString() всегда возвращает nil

#ios #xcode #ios7 #xcode5 #swift

#iOS #xcode #ios7 #xcode5 #swift

Вопрос:

Следующий код выводится, nil несмотря ListCell на то, что это допустимый класс.

 var lCellClass : AnyClass! = NSClassFromString("ListCell");

println(lCellClass);
  

В документах говорится, что метод возвращает

Объект класса с именем aClassName или nil , если в данный момент не загружен класс с таким именем. Если имя_акласса равно nil , возвращается nil .

Я также пытался получить NSClassFromString() от текущего viewcontroller, который загружен, но все равно получаю nil

В чем может быть проблема?

Обновление: Даже пытаясь сделать это NSClassFromString("Array") , я все еще получаю nil

Комментарии:

1. «Даже пытаясь сделать это, NSClassFromString(«Массив») Я все еще получаю nil» Массив<T> — это структура, а не класс.

Ответ №1:

NSClassFromString Функция работает для (чистых и производных от Objective-C) классов swift, но только если вы используете полное имя.

Например, в модуле, вызываемом MyApp с помощью чистого класса swift, называемого Person :

 let personClass: AnyClass? = NSClassFromString("MyApp.Person")
  

Имя модуля определяется параметром сборки «Product Module Name» ( PRODUCT_MODULE_NAME ), обычно тем же именем, что и ваша цель (с некоторой нормализацией, применяемой, например, для удаления пробелов).

Это нетипично, но если класс, который вы загружаете, находится в текущем модуле, и вы не знаете имени модуля во время компиляции, например, потому что код компилируется как часть нескольких целевых объектов, вы можете динамически искать имя пакета, которое обычно соответствует имени модуля:

 let moduleName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let personClass: AnyClass? = NSClassFromString(moduleName   "."   "Person")
  

Однако я не рекомендую это, если вы действительно не знаете во время компиляции.

Смотрите Использование имен классов Swift с API Objective-C в разделе Использование Swift с Cocoa и Objective-C для получения дополнительной информации.

Комментарии:

1. Интересно! Спасибо за это.

2. И вот почему я так люблю!!

3. 1 Просто любопытно, задокументировано ли это где-нибудь подобным образом?

4. В настоящее время нет, пожалуйста, отправьте отчет об ошибке в документации swift по адресу bugreport.apple.com

5. В вашем примере «MyApp» было бы целевым именем, а не названием проекта. Таким образом, универсальный пример для «MyCustomClass» был бы чем-то вроде: NSClassFromString(Bundle.main.infoDictionary!["CFBundleName"] as! String "." "MyCustomClass")

Ответ №2:

Также можно указать имя для символа в Objective-C, которое опускает пространство имен в objective C, используя аннотацию @objc. Если вы предпочитаете использовать имя без модуля, просто используйте то же имя класса:

 @objc(Foobar)
class Foobar{

}
  

NSClassFromString(«Foobar») вернет класс Foobar.

Комментарии:

1. На самом деле, это самый релевантный ответ. Спасибо.

2. Вы не должны делать это только для того, чтобы печатать немного меньше при использовании NSClassFromString . Вы теряете все преимущества пространства имен. Вы не «определяете пространство имен класса swift», вы удаляете все пространство имен.

3. Поддерживает ли objective C пространства имен сейчас?

4. Нет. Этого никогда не было и никогда не будет. Как только вы добавите их, вы получите быстрый и хрупкий способ метапрограммирования, используя рецепт JackLawrence.

Ответ №3:

Возможно, проблема в том, что ваш класс не расширен из NSObject. Поскольку по умолчанию swift не имеет суперкласса.

Ответ №4:

Например:

Просто используя UIViewController в качестве примера,

 func getVc(from stringName: String) -> UIViewController? {
    let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
    guard let vc = NSClassFromString(appName   "."   stringName) as? UIViewController.Type else {
        return nil
    }
    return vc.init()
}
  

Если имя вашего приложения содержит «-» или число, просто замените их на «_»