NSClassFromString() always returns nil - ios

The following code prints nil, despite ListCell is a valid class.
var lCellClass : AnyClass! = NSClassFromString("ListCell");
println(lCellClass);
The docs are saying that method returns
The class object named by aClassName, or nil if no class by that name is currently loaded. If aClassName is nil, returns nil.
I also tried to get NSClassFromString() of current viewcontroller which is LOADED but still get nil
What can be the problem ?
Update:
Even trying to do this NSClassFromString("Array") I still get nil

The NSClassFromString function does work for (pure and Objective-C-derived) swift classes, but only if you use the fully qualified name.
For example, in a module called MyApp with a pure swift class called Person:
let personClass: AnyClass? = NSClassFromString("MyApp.Person")
The module name is defined by the "Product Module Name" (PRODUCT_MODULE_NAME) build setting, typically the same name as your target (with some normalization applied to e.g. remove spaces).
This is atypical, but if the class you're loading is in the current module and you don't know the module name at compile-time e.g. because the code is compiled as part of multiple targets, you can look up the bundle name dynamically, which usually corresponds to the module name:
let moduleName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let personClass: AnyClass? = NSClassFromString(moduleName + "." + "Person")
I don't recommend this however unless you really don't know at compile-time.
See Using Swift Class Names with Objective-C APIs in Using Swift With Cocoa and Objective-C for more information.

It's also possible to specify a name for the symbol in Objective-C which omits the namespace in objective C by using the #objc annotation. If you prefer to use the name without the module, just use the same class name:
#objc(Foobar)
class Foobar{
}
NSClassFromString("Foobar") will return the class Foobar.

This may be problem that your class have not extend from NSObject. As by default swift does not have superclass.

For example:
Just using UIViewController as an example,
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()
}
If your App name contains "-" or number, just replace them with "_"

Related

Can #dynamicMemberLookup be used to call methods?

In the documentation for #dynamicMemberLookup it says,
Apply this attribute to a class, structure, enumeration, or protocol to enable members to be looked up by name at runtime.
If I'm not mistaken, instance methods are considered members of a struct / class. However, when I try to call a function dynamically I get an error saying:
Dynamic key path member lookup cannot refer to instance method foo()
To reproduce the problem:
struct Person {
var name: String
var age: Int
func greet() {
print("hello, my name is \(name)")
}
}
#dynamicMemberLookup
struct Wrapper {
var value: Person
subscript<T>(dynamicMember keypath: KeyPath<Person, T>) -> T {
value[keyPath: keypath]
}
}
let person = Person(name: "John Doe", age: 21)
let wrapper = Wrapper(value: person)
wrapper.greet() // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
// Or
let function = wrapper.greet // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
function()
How can I dynamically call greet() using #dynamicMemberLookup? Is there any way to achieve what I'm trying to do?
Thanks in advance!
No, dynamicMemberLookup does not work for methods. As the signature of the subscript suggests, it only works for things that can be represented as a KeyPath. Method calls cannot be part of a key path. :(
Key-Path Expression
A key-path expression refers to a property or subscript of a type.
The path consists of property names, subscripts, optional-chaining
expressions, and forced unwrapping expressions. Each of these key-path
components can be repeated as many times as needed, in any order.
At compile time, a key-path expression is replaced by an instance of
the KeyPath class.
I suspect the reason why it is called "dynamic member lookup" is because it also works with subscripts. The alternative of dynamicPropertyOrSubscriptLookup is rather a mouthful isn't it?
One rather hacky fix would be to change greet into a computed property:
var greet: () -> Void { {
print("hello, my name is \(name)")
} }
If greet has had parameters, you could also change it into a subscript, but I think that is an even uglier solution.

How do I use Key-Value Coding in Swfit 4.0?

I never used Swift4 before, and dont know how to use KVC in it.
I try to create model with Dictionary, here the code:
class Person : NSObject {
var name: String = ""
var age: Int = 0
init(dict: [String : Any]) {
super.init()
self.setValuesForKeys(dict)
}
}
let dict: [String : Any] = ["name" : "Leon", "age" : 18]
let p = Person(dict: dict)
print(p.name, p.age)
There I get two question:
1. Why dont I using AnyObject? "Leon"and18 was infer to String and Int, does it using in KVC?
2. #objc var name: String = "" , this form is worked, but I can not understand it.
Thanks for all helps.
To implement KVC support for a property in Swift 4, you need two things:
Since the current implementation of KVC is written in Objective-C, you need the #objc annotation on your property so that Objective-C can see it. This also means that the property's type needs to be compatible with Objective-C.
In addition to exposing the property to Objective-C, you will need to set up your notifications in order for observers to be notified when the property changes. There are three ways to do this:
For stored properties, the easiest thing to do is to add the dynamic keyword like so:
#objc dynamic var foo: String
This will allow Cocoa to use Objective-C magic to automagically generate the needed notifications for you, and is usually what you want. However, if you need finer control, you can also write the notification code manually:
#objc private static let automaticallyNotifiesObserversOfFoo = false
#objc var foo: String {
willSet { self.willChangeValue(for: \.foo) }
didSet { self.didChangeValue(for: \.foo) }
}
The automaticallyNotifiesObserversOf<property name> property is there to signify to the KVC/KVO system that we are handling the notifications ourselves and that Cocoa shouldn't try to generate them for us.
Finally, if your property is not stored, but rather depends on some other property or properties, you need to implement a keyPathsForValuesAffecting<your property name here> method like so:
#objc dynamic var foo: Int
#objc dynamic var bar: Int
#objc private static let keyPathsForValuesAffectingBaz: Set<String> = [
#keyPath(foo), #keyPath(bar)
]
#objc var baz: Int { return self.foo + self.bar }
In the example above, an observer of the baz property will be notified when the value for foo or the value for bar changes.
Everything was right for me but still I was getting this error, then I solved it by
Enabling the "Inherit module from Target" in the Identity Inspector.
or
Giving the module(usually folder name/group name) in which it is present from the Identity Inspector under Custom Class
your code
var name: String = ""
var age: Int = 0
you can write the same code like this, when you are sure about its type.
var name = ""
var age = 0
Any is generally used for all types(function types and optional types), while AnyObject is used for Class types.
#objc have different meaning, when you use #objc in your swift class, that code is available in objective-c. You should use #objc attribute to specify same as objective-c class, in result older archives can be replaced by new swift class.

Instatiate Realm Object from string in swift 3

I would like to know if it is possible to instantiate a realm object based on a string that is the class name of the realm object but without knowing what that string will be until it is provided.
For example:
for(_, object) in json["AllObjects"]{
let objectType = self.getRealmObjectBasedOnString(type: className, params: object.stringValue)
self.objectList.append(objectType)
}
Here I go through a json that I get and want to create a realm object from each json object in the array. The problem is that this method will be called several times and each time the only thing that will change is the className variable. So I would like to keep this logic in only one method instead of creating several methods with same logic or a huge and complicated if else that determines the realm object to be created.
Here is getRealmObjectBasedOnString
func getRealmObjectBasedOnString(type: String, params: String) -> Object{
switch type {
case "classA":
return ClassA(JSONString: params)!
case "classB":
return ClassB(JSONString: params)!
default:
return DefaultClass(JSONString: params)!
}
}
Can someone explain why this does not work and whether it is possible to accomplish what I want?
You can use NSClassFromString to get Realm object type from string, but keep in mind that Swift uses modules for nemespacing, so you'll need to add your app's module name before your class name.
guard let objectType = NSClassFromString("YourAppModuleName.\(json["className")") else {
// handle unexpected class here
}
let objectList = realm.objects(objectType)

Get the class type name of a UIView subclass in Swift [duplicate]

Is there a way to print the runtime type of a variable in swift? For example:
var now = NSDate()
var soon = now.dateByAddingTimeInterval(5.0)
println("\(now.dynamicType)")
// Prints "(Metatype)"
println("\(now.dynamicType.description()")
// Prints "__NSDate" since objective-c Class objects have a "description" selector
println("\(soon.dynamicType.description()")
// Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method
In the example above, I'm looking for a way to show that the variable "soon" is of type ImplicitlyUnwrappedOptional<NSDate>, or at least NSDate!.
Update September 2016
Swift 3.0: Use type(of:), e.g. type(of: someThing) (since the dynamicType keyword has been removed)
Update October 2015:
I updated the examples below to the new Swift 2.0 syntax (e.g. println was replaced with print, toString() is now String()).
From the Xcode 6.3 release notes:
#nschum points out in the comments that the Xcode 6.3 release notes show another way:
Type values now print as the full demangled type name when used with
println or string interpolation.
import Foundation
class PureSwiftClass { }
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")
print( "String(Int.self) -> \(Int.self)")
print( "String((Int?).self -> \((Int?).self)")
print( "String(NSString.self) -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")
Which outputs:
String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self) -> Int
String((Int?).self -> Optional<Int>
String(NSString.self) -> NSString
String(Array<String>.self) -> Array<String>
Update for Xcode 6.3:
You can use the _stdlib_getDemangledTypeName():
print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")
and get this as output:
TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String
Original answer:
Prior to Xcode 6.3 _stdlib_getTypeName got the mangled type name of a variable. Ewan Swick's blog entry helps to decipher these strings:
e.g. _TtSi stands for Swift's internal Int type.
Mike Ash has a great blog entry covering the same topic.
Edit: A new toString function has been introduced in Swift 1.2 (Xcode 6.3).
You can now print the demangled type of any type using .self and any instance using .dynamicType:
struct Box<T> {}
toString("foo".dynamicType) // Swift.String
toString([1, 23, 456].dynamicType) // Swift.Array<Swift.Int>
toString((7 as NSNumber).dynamicType) // __NSCFNumber
toString((Bool?).self) // Swift.Optional<Swift.Bool>
toString(Box<SinkOf<Character>>.self) // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>>
toString(NSStream.self) // NSStream
Try calling YourClass.self and yourObject.dynamicType.
Reference: https://devforums.apple.com/thread/227425.
Swift 3.0
let string = "Hello"
let stringArray = ["one", "two"]
let dictionary = ["key": 2]
print(type(of: string)) // "String"
// Get type name as a string
String(describing: type(of: string)) // "String"
String(describing: type(of: stringArray)) // "Array<String>"
String(describing: type(of: dictionary)) // "Dictionary<String, Int>"
// Get full type as a string
String(reflecting: type(of: string)) // "Swift.String"
String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>"
String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>"
Is this what you're looking for?
println("\(object_getClassName(now))");
It prints "__NSDate"
UPDATE: Please note this no longer seems to work as of Beta05
My current Xcode is Version 6.0 (6A280e).
import Foundation
class Person { var name: String; init(name: String) { self.name = name }}
class Patient: Person {}
class Doctor: Person {}
var variables:[Any] = [
5,
7.5,
true,
"maple",
Person(name:"Sarah"),
Patient(name:"Pat"),
Doctor(name:"Sandy")
]
for variable in variables {
let typeLongName = _stdlib_getDemangledTypeName(variable)
let tokens = split(typeLongName, { $0 == "." })
if let typeName = tokens.last {
println("Variable \(variable) is of Type \(typeName).")
}
}
Output:
Variable 5 is of Type Int.
Variable 7.5 is of Type Double.
Variable true is of Type Bool.
Variable maple is of Type String.
Variable Swift001.Person is of Type Person.
Variable Swift001.Patient is of Type Patient.
Variable Swift001.Doctor is of Type Doctor.
As of Xcode 6.3 with Swift 1.2, you can simply convert type values into the full demangled String.
toString(Int) // "Swift.Int"
toString(Int.Type) // "Swift.Int.Type"
toString((10).dynamicType) // "Swift.Int"
println(Bool.self) // "Swift.Bool"
println([UTF8].self) // "Swift.Array<Swift.UTF8>"
println((Int, String).self) // "(Swift.Int, Swift.String)"
println((String?()).dynamicType)// "Swift.Optional<Swift.String>"
println(NSDate) // "NSDate"
println(NSDate.Type) // "NSDate.Type"
println(WKWebView) // "WKWebView"
toString(MyClass) // "[Module Name].MyClass"
toString(MyClass().dynamicType) // "[Module Name].MyClass"
You can still access the class, through className (which returns a String).
There are actually several ways to get the class, for example classForArchiver, classForCoder, classForKeyedArchiver (all return AnyClass!).
You can't get the type of a primitive (a primitive is not a class).
Example:
var ivar = [:]
ivar.className // __NSDictionaryI
var i = 1
i.className // error: 'Int' does not have a member named 'className'
If you want to get the type of a primitive, you have to use bridgeToObjectiveC(). Example:
var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber
You can use reflect to get information about object.
For example name of object class:
var classname = reflect(now).summary
Xcode 8 Swift 3.0 use type(of:)
let className = "\(type(of: instance))"
I had luck with:
let className = NSStringFromClass(obj.dynamicType)
SWIFT 5
With the latest release of Swift 3 we can get pretty descriptions of type names through the String initializer. Like, for example print(String(describing: type(of: object))). Where object can be an instance variable like array, a dictionary, an Int, a NSDate, an instance of a custom class, etc.
Here is my complete answer: Get class name of object as string in Swift
That question is looking for a way to getting the class name of an object as string but, also i proposed another way to getting the class name of a variable that isn't subclass of NSObject. Here it is:
class Utility{
class func classNameAsString(obj: Any) -> String {
//prints more readable results for dictionaries, arrays, Int, etc
return String(describing: type(of: obj))
}
}
I made a static function which takes as parameter an object of type Any and returns its class name as String :) .
I tested this function with some variables like:
let diccionary: [String: CGFloat] = [:]
let array: [Int] = []
let numInt = 9
let numFloat: CGFloat = 3.0
let numDouble: Double = 1.0
let classOne = ClassOne()
let classTwo: ClassTwo? = ClassTwo()
let now = NSDate()
let lbl = UILabel()
and the output was:
diccionary is of type Dictionary
array is of type Array
numInt is of type Int
numFloat is of type CGFloat
numDouble is of type Double
classOne is of type: ClassOne
classTwo is of type: ClassTwo
now is of type: Date
lbl is of type: UILabel
In Xcode 8, Swift 3.0
Steps:
1. Get the Type:
Option 1:
let type : Type = MyClass.self //Determines Type from Class
Option 2:
let type : Type = type(of:self) //Determines Type from self
2. Convert Type to String:
let string : String = "\(type)" //String
In Swift 3.0, you can use type(of:), as dynamicType keyword has been removed.
To get a type of object or class of object in Swift, you must need to use a type(of: yourObject)
type(of: yourObject)
When using Cocoa (not CocoaTouch), you can use the className property for objects that are subclasses of NSObject.
println(now.className)
This property is not available for normal Swift objects, which aren't subclasses of NSObject (and in fact, there is no root id or object type in Swift).
class Person {
var name: String?
}
var p = Person()
println(person.className) // <- Compiler error
In CocoaTouch, at this time there is not a way to get a string description of the type of a given variable. Similar functionality also does not exist for primitive types in either Cocoa or CocoaTouch.
The Swift REPL is able to print out a summary of values including its type, so it is possible this manner of introspection will be possible via an API in the future.
EDIT: dump(object) seems to do the trick.
The top answer doesn't have a working example of the new way of doing this using type(of:. So to help rookies like me, here is a working example, taken mostly from Apple's docs here - https://developer.apple.com/documentation/swift/2885064-type
doubleNum = 30.1
func printInfo(_ value: Any) {
let varType = type(of: value)
print("'\(value)' of type '\(varType)'")
}
printInfo(doubleNum)
//'30.1' of type 'Double'
I've tried some of the other answers here but milage seems to very on what the underling object is.
However I did found a way you can get the Object-C class name for an object by doing the following:
now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for
Here is and example of how you would use it:
let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")
In this case it will print NSDate in the console.
I found this solution which hopefully might work for someone else.
I created a class method to access the value. Please bear in mind this will work for NSObject subclass only. But at least is a clean and tidy solution.
class var className: String!{
let classString : String = NSStringFromClass(self.classForCoder())
return classString.componentsSeparatedByString(".").last;
}
In the latest XCode 6.3 with Swift 1.2, this is the only way I found:
if view.classForCoder.description() == "UISegment" {
...
}
Many of the answers here do not work with the latest Swift (Xcode 7.1.1 at time of writing).
The current way of getting the information is to create a Mirror and interrogate that. For the classname it is as simple as:
let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description
Additional information about the object can also be retrieved from the Mirror. See http://swiftdoc.org/v2.1/type/Mirror/ for details.
Swift version 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
Thanks #Joshua Dance
In lldb as of beta 5, you can see the class of an object with the command:
fr v -d r shipDate
which outputs something like:
(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940
The command expanded out means something like:
Frame Variable (print a frame variable) -d run_target (expand dynamic types)
Something useful to know is that using "Frame Variable" to output variable values guarantees no code is executed.
I've found a solution for self-developed classes (or such you have access to).
Place the following computed property within your objects class definition:
var className: String? {
return __FILE__.lastPathComponent.stringByDeletingPathExtension
}
Now you can simply call the class name on your object like so:
myObject.className
Please note that this will only work if your class definition is made within a file that is named exactly like the class you want the name of.
As this is commonly the case the above answer should do it for most cases. But in some special cases you might need to figure out a different solution.
If you need the class name within the class (file) itself you can simply use this line:
let className = __FILE__.lastPathComponent.stringByDeletingPathExtension
Maybe this method helps some people out there.
Based on the answers and comments given by Klass and Kevin Ballard above, I would go with:
println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!)
which will print out:
"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"
"NSString"
"PureSwiftClass"
"Int"
"Double"
let i: Int = 20
func getTypeName(v: Any) -> String {
let fullName = _stdlib_demangleName(_stdlib_getTypeName(i))
if let range = fullName.rangeOfString(".") {
return fullName.substringFromIndex(range.endIndex)
}
return fullName
}
println("Var type is \(getTypeName(i)) = \(i)")
Swift 4:
// "TypeName"
func stringType(of some: Any) -> String {
let string = (some is Any.Type) ? String(describing: some) : String(describing: type(of: some))
return string
}
// "ModuleName.TypeName"
func fullStringType(of some: Any) -> String {
let string = (some is Any.Type) ? String(reflecting: some) : String(reflecting: type(of: some))
return string
}
Usage:
print(stringType(of: SomeClass())) // "SomeClass"
print(stringType(of: SomeClass.self)) // "SomeClass"
print(stringType(of: String())) // "String"
print(fullStringType(of: String())) // "Swift.String"
There appears to be no generic way to print the type name of an arbitrary value's type. As others have noted, for class instances you can print value.className but for primitive values it appears that at runtime, the type information is gone.
For instance, it looks as if there's not a way to type: 1.something() and get out Int for any value of something. (You can, as another answer suggested, use i.bridgeToObjectiveC().className to give you a hint, but __NSCFNumber is not actually the type of i -- just what it will be converted to when it crosses the boundary of an Objective-C function call.)
I would be happy to be proven wrong, but it looks like the type checking is all done at compile time, and like C++ (with RTTI disabled) much of the type information is gone at runtime.
This is how you get a type string of your object or Type which is consistent and takes into account to which module the object definition belongs to or nested in. Works in Swift 4.x.
#inline(__always) func typeString(for _type: Any.Type) -> String {
return String(reflecting: type(of: _type))
}
#inline(__always) func typeString(for object: Any) -> String {
return String(reflecting: type(of: type(of: object)))
}
struct Lol {
struct Kek {}
}
// if you run this in playground the results will be something like
typeString(for: Lol.self) // __lldb_expr_74.Lol.Type
typeString(for: Lol()) // __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)// __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek()) // __lldb_expr_74.Lol.Kek.Type
Not exactly what you are after, but you can also check the type of the variable against Swift types like so:
let object: AnyObject = 1
if object is Int {
}
else if object is String {
}
For example.
Xcode 7.3.1, Swift 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last

Swift class "MyClass" does not have a member Named "My_Var" [duplicate]

This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 8 years ago.
I created a class in Swift like below, but it gives error:
'ApiUrls.Type' does not have a member named 'webUrl'
Here is my code:
import UIKit
class ApiUrls {
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = webUrl + NSString("dev/sys/getkey") // here comes the error ApiUrls.Type' does not have a member named 'webUrl
}
What's wrong in it?
You cannot initialize an instance property with the value of another property, because self is not available until all instance properties have been initialized.
Even moving the properties initialization in an initializer doesn't work, because getKey relies on webUrl, so getKey cannot be initialized until itself is initialized.
I see that webUrl is a constant, so maybe it's a good idea to make it a static property - classes don't support statics as of yet, so the best way is to use a private struct:
class ApiUrls {
private struct Static {
static let webUrl: String = "192.168.0.106:8888"
}
var getKey: String = Static.webUrl + "dev/sys/getkey"
}
Also, unless you have a good reason, it's better to use swift strings and not NSString.
As far as I know, you cannot initialise variables like that in the class definition.
Try declaring your variables as
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = ""
and add this in viewDidLoad
getKey = webUrl + NSString("dev/sys/getkey")

Resources