I am trying to associated a property to an Array Extension:
private var AssociatedObjectHandle: String = "BlaBLabla"
extension Array {
var emptyIndex:Int {
mutating get {
if let object = objc_getAssociatedObject(self, &AssociatedObjectHandle) {
return object as! Int
}
let index = self.searchEmptyIndex()
self.emptyIndex = index
return index
}
set {
let new = (newValue as NSInteger)
objc_setAssociatedObject(self, &AssociatedObjectHandle, new, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
func searchEmptyIndex() -> Int {
if let arr = self as? [Int] {
return arr.index(of: -1)!
}
return -1
}
}
The objc_getAssociatedObject call always returns nil!!
Anyone has any idea why?
I am banging my head for the last hour about this...
You cannot add associated objects to a Swift Array (or any Swift value type).
objc_setAssociatedObject() and objc_getAssociatedObject() are from the
Objective-C runtime, they expect an instance of NSObject as first
argument.
Your code compiles and runs only because any Swift value is automatically
bridged to an object if necessary.
When you call objc_setAssociatedObject(self, ...) then self
is bridged to a (temporary) instance of NSArray, and the association
is made on that object.
Later, when objc_getAssociatedObject(self, ...) is called,
another (temporary) instance of NSArray is created, and that
has no associated object.
That's why you get nil as the result.
I am trying to reference a property in my class from a closure declared in my class. I cannot access self from inside my closure, and I'm assuming self would refer to the Class API from within my closure.
I want to declare a closure that I use later as a parameter to pass to a URLSession dataTask (It works without the one error line). I get the error listed in the title.
Use of unresolved identifier 'self'
I've been writing swift for an entire day now and am just trying things out as a sandbox, so I fully expect some criticism.
class Api {
struct Location {
var name = String()
var author = String()
var averageRating: String?
var id = Int()
var lat = Double()
var lon = Double()
var type = String()
}
var locations = [Location]()
var doSomething = {(data: Data?, response: URLResponse?, error: Error?) -> Void in
if error != nil {
print(error!.localizedDescription)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
let myResult = json["results"] as! [[String: Any]]
var location : Location! = Location()
for jsonLocation in myResult {
if let name = jsonLocation["name"]{location.name = name as! String}
if let author = jsonLocation["author"]{location.author = author as! String}
if let id = jsonLocation["id"]{location.id = id as! Int}
if let lat = jsonLocation["lat"]{location.lat = lat as! Double}
if let lon = jsonLocation["lon"]{location.lon = lon as! Double}
if let type = jsonLocation["type"]{location.type = type as! String}
//ERROR IS HERE, Why does self not reference class API?
self.locations.append(location)
}
}
} catch {
print("error in JSONSerialization")
}
}
}
}
I have found this, but this example is different so I wasn't sure if it was the same bug or me not understanding swift.
Rahul's explanation is correct, but the suggested answer is ever so slightly incomplete.
Here is a complete solution:
Declare the doSomething property as lazy as Rahul suggested. A lazy stored property is a property whose initial value is not calculated until the first time it is used. In other words this closure will not be evaluated until the doSomething property is called at run-time, at which point self is guaranteed to exist. See Lazy Stored Properties in the Swift Programming Language for more details.
Add a type annotation to the doSomething property so the compiler doesn't have to infer the type at compile time, which apparently it can't do because the closure includes self. See Type Safety and Type Inference in the Swift Programming Language for more details.
So the complete declaration is:
...
lazy var doSomething: (Data?, URLResponse?, Error?) -> Void = { (data: Data?, response: URLResponse?, error: Error?) -> Void in
...
ps. Welcome to Swift programming! It's a fantastic language and really fun. I hope you enjoy it as much as I do.
You are not able to access self because it is not available when you are calling inside the closure as initialization hasn't happened yet and so compiler gives you the error.
The fix would be to user lazy var as this will defer the self call because lazy var get called only after initialisation.
lazy var doSomething = { your closure goes here }
I have the same questions as you and I solve it using lazy var
Here is a quick example
My originally code is:
class MyClass {
let callback:()->() = {
self.foo() // Compile error: Use of unresolved identifier "self"
}
func foo() {
print("bar")
}
}
It compile error at that line I use self
But I change it to
class MyClass {
lazy var callback:()->() = {
[unowned self] in
self.foo()
}
func foo() {
print("bar")
}
}
let c = MyClass()
c.callback()
that solved the problem
References:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
http://mikebuss.com/2014/06/22/lazy-initialization-swift/
Shall we always use [unowned self] inside closure in Swift
Replace var locations = [Location]() with this var locations : [Location]?
and var location : Location! = Location() with self.locations = [Location]() and self.locations.append(location) with self.locations?.append(location)
You will be good to go!
lazy var is too complex a concept to grasp I guess but you can use it this way:
lazy var locations:[Location] = {
let locations = Location()
return locations
}()
I am looking for best way how can I make this code to one line:
if (dictionary["Amoumt"] is Double) {
amount = dictionary["Amount"] as Double
} else {
amount = NSString(string: dictionary["Amount"] as String).doubleValue
}
I have Dictionary<String, AnyObject> and I would like to parse values from it. I am using code like above but it's too many lines. I would like to make it to one line. Something like:
dictionary["Amount"].parseDouble()
There is no problem to create extension with this method:
func parseDouble() -> Double {
if (self is Double) {
return self as Double
} else {
return NSString(string:(self as String)).doubleValue
}
}
But which type should I extend? Next could you help me with generic method? So I could call something like this:
dictionary["Amount"].parse(Double)
And is this good way how to do this or should I do it another way?
You can use AnyObject as is. Try:
var dictionary:[String:AnyObject] = [
"foo": 4.21, // NSNumber
"bar": "42.5", // NSString
"baz": [1,2,3], // NSArray
]
let foo = dictionary["foo"]?.doubleValue ?? 0 // -> 4.21
let bar = dictionary["bar"]?.doubleValue ?? 0 // -> 42.5
let baz = dictionary["baz"]?.doubleValue ?? 0 // -> 0.0
This works because both NSNumber and NSString have .doubleValue property.
On the other hand, NSArray does not have that property, in this case it returns nil.
As described in the document:
You can also call any Objective-C method and access any property without casting to a more specific class type. This includes Objective-C compatible methods marked with the #objc attribute.
Maybe you are looking for this kind of extenison:
extension Dictionary{
func parseDouble(key:Key) -> Double {
let result = self[key]
if (result is Double) {
return result as Double
} else {
return NSString(string:(result as String)).doubleValue
}
}
}
And getting value for key by using this:
var doubleValue = dictionary.parseDouble("amount")
And a generic function
extension Dictionary{
func parse<T>(key:Key) -> T? {
let result = self[key]
if (result is T) {
return result as? T
}
return nil
}
}
var doubleValue:Double? = myDistionary.parse("someKeyForDouble")
var stringValue:String? = myDistionary.parse("someKeyForString")
The easiest way to condense this is to use the nil coalescing operator and an optional double. This attempts to cast the value as a double. If it succeeds, it unwraps it, if it fails, it defaults to the second value, which comes from converting `dict[amount]' to a string and taking its double value.
var amount: Double? = nil
let dict: [String: AnyObject] = ["amount" : "1.2"]
amount = (dict["amount"] as? Double) ?? NSString(string: dict["amount"] as! String).doubleValue
And to make your function:
func getDouble(obj: AnyObject) -> Double {
return (obj as? Double) ?? NSString(string: obj as! String).doubleValue
}
and you call it using getDouble(dict["amount"]). An extension for something like this is probably overkill in my opinion.
If you wanted an extension, the best place to put it in theory would be AnyObject – because it is an AnyObject that you want to convert.
But AnyObject is actually a protocol, so you can't extend it.
I wouldn't recommend putting it as an extension to Dictionary – the coercing of a type into a double is not really anything to do with dictionaries.
So the best approach is to do it as a free function not as an extension:
func getDouble(obj: AnyObject?) -> Double {
return (obj as? Double) ?? (obj as? NSString)?.doubleValue ?? 0
}
asDouble(dictionary["Amount"])
Note, this function is safe if you pass it a function that is neither a double nor a string. Other solutions using as or ! instead of as? will crash at runtime if you ever pass something else in.
You could argue it should return an optional, with nil if the value was not convertible to a double. This is what String.toInt() does. Unfortunately, the limitation of NSString.doubleValue is that it doesn't do this – it defaults to zero instead – so you can't combine these two approaches.
Getting the classname of an object as String using:
object_getClassName(myViewController)
returns something like this:
_TtC5AppName22CalendarViewController
I am looking for the pure version: "CalendarViewController". How do I get a cleaned up string of the class name instead?
I found some attempts of questions about this but not an actual answer. Is it not possible at all?
String from an instance:
String(describing: self)
String from a type:
String(describing: YourType.self)
Example:
struct Foo {
// Instance Level
var typeName: String {
return String(describing: Foo.self)
}
// Instance Level - Alternative Way
var otherTypeName: String {
let thisType = type(of: self)
return String(describing: thisType)
}
// Type Level
static var typeName: String {
return String(describing: self)
}
}
Foo().typeName // = "Foo"
Foo().otherTypeName // = "Foo"
Foo.typeName // = "Foo"
Tested with class, struct and enum.
UPDATED TO SWIFT 5
We can get pretty descriptions of type names using the instance variable through the String initializer and create new objects of a certain class
Like, for example print(String(describing: type(of: object))). Where object can be an instance variable like array, a dictionary, an Int, a NSDate, etc.
Because NSObject is the root class of most Objective-C class hierarchies, you could try to make an extension for NSObject to get the class name of every subclass of NSObject. Like this:
extension NSObject {
var theClassName: String {
return NSStringFromClass(type(of: self))
}
}
Or you could make a static funcion whose parameter is of type Any (The protocol to which all types implicitly conform) and returns the class name as String. Like this:
class Utility{
class func classNameAsString(_ obj: Any) -> String {
//prints more readable results for dictionaries, arrays, Int, etc
return String(describing: type(of: obj))
}
}
Now you can do something like this:
class ClassOne : UIViewController{ /* some code here */ }
class ClassTwo : ClassOne{ /* some code here */ }
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Get the class name as String
let dictionary: [String: CGFloat] = [:]
let array: [Int] = []
let int = 9
let numFloat: CGFloat = 3.0
let numDouble: Double = 1.0
let classOne = ClassOne()
let classTwo: ClassTwo? = ClassTwo()
let now = NSDate()
let lbl = UILabel()
print("dictionary: [String: CGFloat] = [:] -> \(Utility.classNameAsString(dictionary))")
print("array: [Int] = [] -> \(Utility.classNameAsString(array))")
print("int = 9 -> \(Utility.classNameAsString(int))")
print("numFloat: CGFloat = 3.0 -> \(Utility.classNameAsString(numFloat))")
print("numDouble: Double = 1.0 -> \(Utility.classNameAsString(numDouble))")
print("classOne = ClassOne() -> \((ClassOne).self)") //we use the Extension
if classTwo != nil {
print("classTwo: ClassTwo? = ClassTwo() -> \(Utility.classNameAsString(classTwo!))") //now we can use a Forced-Value Expression and unwrap the value
}
print("now = Date() -> \(Utility.classNameAsString(now))")
print("lbl = UILabel() -> \(String(describing: type(of: lbl)))") // we use the String initializer directly
}
}
Also, once we can get the class name as String, we can instantiate new objects of that class:
// Instantiate a class from a String
print("\nInstantiate a class from a String")
let aClassName = classOne.theClassName
let aClassType = NSClassFromString(aClassName) as! NSObject.Type
let instance = aClassType.init() // we create a new object
print(String(cString: class_getName(type(of: instance))))
print(instance.self is ClassOne)
Maybe this helps someone out there!.
Swift 5
Here is the extension to get the typeName as a variable (work with both value type or reference type).
protocol NameDescribable {
var typeName: String { get }
static var typeName: String { get }
}
extension NameDescribable {
var typeName: String {
return String(describing: type(of: self))
}
static var typeName: String {
return String(describing: self)
}
}
How to use:
// Extend with class/struct/enum...
extension NSObject: NameDescribable {}
extension Array: NameDescribable {}
extension UIBarStyle: NameDescribable { }
print(UITabBarController().typeName)
print(UINavigationController.typeName)
print([Int]().typeName)
print(UIBarStyle.typeName)
// Out put:
UITabBarController
UINavigationController
Array<Int>
UIBarStyle
Swift 5.2:
String(describing: type(of: self))
Swift 3.0
String(describing: MyViewController.self)
I suggest such an approach (very Swifty):
// Swift 3
func typeName(_ some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}
// Swift 2
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
It doesn't use neither introspection nor manual demangling (no magic!).
Here is a demo:
// Swift 3
import class Foundation.NSObject
func typeName(_ some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}
class GenericClass<T> {
var x: T? = nil
}
protocol Proto1 {
func f(x: Int) -> Int
}
#objc(ObjCClass1)
class Class1: NSObject, Proto1 {
func f(x: Int) -> Int {
return x
}
}
struct Struct1 {
var x: Int
}
enum Enum1 {
case X
}
print(typeName(GenericClass<Int>.self)) // GenericClass<Int>
print(typeName(GenericClass<Int>())) // GenericClass<Int>
print(typeName(Proto1.self)) // Proto1
print(typeName(Class1.self)) // Class1
print(typeName(Class1())) // Class1
print(typeName(Class1().f)) // (Int) -> Int
print(typeName(Struct1.self)) // Struct1
print(typeName(Struct1(x: 1))) // Struct1
print(typeName(Enum1.self)) // Enum1
print(typeName(Enum1.X)) // Enum1
If you have type Foo, the following code will give you "Foo" in Swift 3 and Swift 4:
let className = String(describing: Foo.self) // Gives you "Foo"
The problem with most of the answers on here are that they give you "Foo.Type" as the resulting string when you don't have any instance of the type, when what you really want is just "Foo". The following gives you "Foo.Type", as mentioned in a bunch of the other answers.
let className = String(describing: type(of: Foo.self)) // Gives you "Foo.Type"
The type(of:) part is unnecessary if you just want "Foo".
In Swift 4.1 and now Swift 4.2 :
import Foundation
class SomeClass {
class InnerClass {
let foo: Int
init(foo: Int) {
self.foo = foo
}
}
let foo: Int
init(foo: Int) {
self.foo = foo
}
}
class AnotherClass : NSObject {
let foo: Int
init(foo: Int) {
self.foo = foo
super.init()
}
}
struct SomeStruct {
let bar: Int
init(bar: Int) {
self.bar = bar
}
}
let c = SomeClass(foo: 42)
let s = SomeStruct(bar: 1337)
let i = SomeClass.InnerClass(foo: 2018)
let a = AnotherClass(foo: 1<<8)
If you don't have an instance around:
String(describing: SomeClass.self) // Result: SomeClass
String(describing: SomeStruct.self) // Result: SomeStruct
String(describing: SomeClass.InnerClass.self) // Result: InnerClass
String(describing: AnotherClass.self) // Result: AnotherClass
If you do have an instance around:
String(describing: type(of: c)) // Result: SomeClass
String(describing: type(of: s)) // Result: SomeStruct
String(describing: type(of: i)) // Result: InnerClass
String(describing: type(of: a)) // Result: AnotherClass
Swift 5.1
You can get class, struct, enum, protocol and NSObject names though Self.self.
print("\(Self.self)")
To get name of a Swift class from an object, e.g. for var object: SomeClass(), use
String(describing: type(of: object))
To get name of a Swift class from a class type, e.g. SomeClass, use:
String(describing: SomeClass.self)
Output:
"SomeClass"
You can try this way:
self.classForCoder.description()
To get the type name as a string in Swift 4 (I haven't checked the earlier versions), just use string interpolation:
"\(type(of: myViewController))"
You can use .self on a type itself, and the type(of:_) function on an instance:
// Both constants will have "UIViewController" as their value
let stringFromType = "\(UIViewController.self)"
let stringFromInstance = "\(type(of: UIViewController()))"
You can use the Swift standard library function called _stdlib_getDemangledTypeName like this:
let name = _stdlib_getDemangledTypeName(myViewController)
Swift 5:
Way 1:
print("Class: \(String(describing: self)), Function: \(#function), line: \(#line)")
Output:
Class: <Test.ViewController: 0x7ffaabc0a3d0>, Function: viewDidLoad(), line: 15
Way 2:
print("Class: \(String(describing: type(of: self))), Function: \(#function), line: \(#line)")
Output:
Class: ViewController, Function: viewDidLoad(), line: 16
One can also use mirrors:
let vc = UIViewController()
String(Mirror(reflecting: vc).subjectType)
NB: This method can also be used for Structs and Enums. There is a displayStyle that gives an indication of what type of the structure:
Mirror(reflecting: vc).displayStyle
The return is an enum so you can:
Mirror(reflecting: vc).displayStyle == .Class
Swift 3.0:
You can create an extension like this one.. It gives back the class name without the project name
extension NSObject {
var className: String {
return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last ?? ""
}
public class var className: String {
return NSStringFromClass(self).components(separatedBy: ".").last ?? ""
}
}
You can extend NSObjectProtocol in Swift 4 like this :
import Foundation
extension NSObjectProtocol {
var className: String {
return String(describing: Self.self)
}
}
This will make calculated variable className available to ALL classes. Using this inside a print() in CalendarViewController will print "CalendarViewController" in console.
You can get the name of the class doing something like:
class Person {}
String(describing: Person.self)
To get class name as String declare your class as following
#objc(YourClassName) class YourClassName{}
And get class name using following syntax
NSStringFromClass(YourClassName)
I've been looking for this answer off and on for a while. I use GKStateMachine and like to observe state changes and wanted an easy way to see just the class name. I'm not sure if it's just iOS 10 or Swift 2.3, but in that environment, the following does exactly what I want:
let state:GKState?
print("Class Name: \(String(state.classForCoder)")
// Output:
// Class Name: GKState
Try reflect().summary on Class self or instance dynamicType. Unwrap optionals before getting dynamicType otherwise the dynamicType is the Optional wrapper.
class SampleClass { class InnerClass{} }
let sampleClassName = reflect(SampleClass.self).summary;
let instance = SampleClass();
let instanceClassName = reflect(instance.dynamicType).summary;
let innerInstance = SampleClass.InnerClass();
let InnerInstanceClassName = reflect(innerInstance.dynamicType).summary.pathExtension;
let tupleArray = [(Int,[String:Int])]();
let tupleArrayTypeName = reflect(tupleArray.dynamicType).summary;
The summary is a class path with generic types described. To get a simple class name from the summary try this method.
func simpleClassName( complexClassName:String ) -> String {
var result = complexClassName;
var range = result.rangeOfString( "<" );
if ( nil != range ) { result = result.substringToIndex( range!.startIndex ); }
range = result.rangeOfString( "." );
if ( nil != range ) { result = result.pathExtension; }
return result;
}
The above solutions didn't work for me. The produced mostly the issues mention in several comments:
MyAppName.ClassName
or
MyFrameWorkName.ClassName
This solutions worked on XCode 9, Swift 3.0:
I named it classNameCleaned so it is easier to access and doesn't conflict with future className() changes:
extension NSObject {
static var classNameCleaned : String {
let className = self.className()
if className.contains(".") {
let namesArray = className.components(separatedBy: ".")
return namesArray.last ?? className
} else {
return self.className()
}
}
}
Usage:
NSViewController.classNameCleaned
MyCustomClass.classNameCleaned
Swift 5
NSStringFromClass(CustomClass.self)
This kind of example for class var. Don't include the name of bundle.
extension NSObject {
class var className: String {
return "\(self)"
}
}
Swift 3.0 (macOS 10.10 and later), you can get it from className
self.className.components(separatedBy: ".").last!
I tried type(of:...) in Playground with Swift 3. This is my result.
This is the code format version.
print(String(describing: type(of: UIButton.self)))
print(String(describing: type(of: UIButton())))
UIButton.Type
UIButton
Swift 5.1 :-
You can also use generic function for get class name of object as string
struct GenericFunctions {
static func className<T>(_ name: T) -> String {
return "\(name)"
}
}
Call this function by using following:-
let name = GenericFunctions.className(ViewController.self)
Happy Coding :)
This solution will work for all the classes
Swift 5 solution:
extension NSObject {
var className: String {
return String(describing: type(of: self))
}
class var className: String {
return String(describing: self)
}
}
USAGE:
class TextFieldCell: UITableVIewCell {
}
class LoginViewController: UIViewController {
let cellClassName = TextFieldCell.className
}
If you don't like the mangled name, you can dictate your own name:
#objc(CalendarViewController) class CalendarViewController : UIViewController {
// ...
}
However, it would be better in the long run to learn to parse the mangled name. The format is standard and meaningful and won't change.
Sometimes the other solutions will give a non useful name depending on what object you are trying to look at. In that case you can get the class name as a string using the following.
String(cString: object_getClassName(Any!))
⌘ click the function in xcode to see some related methods that are fairly useful. or check here https://developer.apple.com/reference/objectivec/objective_c_functions
In Object-C I store Class objects in an array and init them dynamically like this:
self.controllers=#[[OneViewController class],[TwoViewController class]];
Class clz = self.controllers[index];
UIViewController *detailViewController = [[clz alloc] init];
In Swift i try this way but it raises an error:
var controllers:AnyClass[] = [OneViewController.self,TwoViewController.self]
var clz : AnyClass = controllers[index]
var instance = clz() // Error:'AnyObject' is not constructible with ()
I wonder Whether there is a way to convert AnyClass to a specific Class?
Or any other good ideas?
You can specify the array to be of the common superclass' type, then type deduction does the right thing (Beta-3 syntax):
let classArray: [UIViewController.Type] = [
OneViewController.self, TwoViewController.self
]
let controllerClass = classArray[index]
let controller = controllerClass.init()
i have found a way to solve this problem:
var controllers:AnyClass[] = [OneViewController.self,TwoViewController.self]
var clz: NSObject.Type = controllers[0] as NSObject.Type
var con = clz()
remember to add #objc in the class of ViewController
An AnyClass variable must first be casted into a specific type in order to initialize an instance:
// Code checked to run on xCode 7.1.1
import UIKit
var aClass: AnyClass = UIButton.self
// Error: 'init' is a member of the type...
// let doesNotWork = aClass.init()
// aClass must be casted first
var buttonClass = aClass as! UIButton.Type
var oneButton = buttonClass!.init()
var otherButton = buttonClass!.init(frame: CGRectZero)
Here is a pure swift implementation of dynamic class types. It does require the classes to extend the same protocol.
protocol ILayout { init(_ a:S tring) }
class A: ILayout { required init(_ a: String) }
class B: ILayout { required init(_ a:String) }
var instance: ILayout
var classType: ILayout.Type
classType = A.self
instance = classType.init("abc")
classType = B.self
instance = classType.init("abc")
If the classes are all Objective-C NSObject subclasses, you can do something like this (yes, the backticks are intentional):
var constructors: (Void -> NSObject!)[] = [ NSMutableString.`new`, NSMutableArray.`new`, NSMutableDictionary.`new` ]
let string = constructors[0]()
(string as NSMutableString).appendString("Hello")
let array = constructors[1]()
(array as NSMutableArray).addObject("Swift")
let dictionary = constructors[2]()
(dictionary as NSMutableDictionary).setObject("Objective-C", forKey: "Goodbye")
NSLog("dynamically created a string: \(string), an array: \(array), and a dictionary: \(dictionary)")
It should output:
dynamically created a string: Hello, an array: (
Swift
), and a dictionary: {
Goodbye = "Objective-C";
}
It does seem to me that there should be a more elegant way to do this.