Failable initializers and stored properties - swift

I have the following class:
class Foo {
let a : Int?
let b : Int?
init?(){
}
}
I get the error "constant self.a used before being initialised" in the failable initialiser. What on earth is the compiler talking about? I haven't used a at all yet!

The problem is that each property declared with let in a class must be populated before the init does return.
In your case the init is not populating the 2 constant properties.
In Swift 2.1 each constant property of a class must be populated even when a failable initializer does fail.
class Foo {
let a: Int?
let b: Int?
init?() {
return nil // compile error
}
}
More details here.
Struct
On the other hand you can use a struct where a failable initializer can return nil without populating all the let properties.
struct Person {
let name: String
init?(name:String?) {
guard let name = name else { return nil }
self.name = name
}
}

Related

Provide class metadata to the generic in swift (Codable)

I have a method that works on Codables and does, among other things, this:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
return nil // or whatever
}
Then i can get myName as the class name at run time to get the right data to create an instance of T.
Now some of my Codable need to provide a custom name for this.
So while i could edit ALL of my codables (a few hundred models) to conform to some protocol that provides name, i really want to avoid doing it.
Since there are no custom attributes in Swift, i concocted this;
protocol MetadataProvidingCodable {
static func customName() -> String
}
Then in my generic i can check whether the T conforms to it:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if T.self is MetadataProvidingCodable.Type {
myName = ... // Get customName() from T without an instance???
}
return nil // or whatever
}
But my problem is that i need to be able to call my static func on the T type without having an instance of T. Is that possible?
You can type cast the T.self as MetadataProvidingCodable.Type like that:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if let type = T.self as? MetadataProvidingCodable.Type {
myName = type.customName()
}
return nil // or whatever
}
Edit: If you can somehow move the common logic to a separate function, you can override the doWhatever() function with another one that return a type that conforms to both Codable and MetadataProvidingCodable.
Then the compiler will figure out what function will call based on the return type:
func doWhatever<T>() -> T? where T: Codable {
print("doWhatever: Codable")
var myName = String(describing: T.self)
return nil
}
func doWhatever<T>() -> T? where T: Codable & MetadataProvidingCodable {
print("doWhatever: Codable & MetadataProvidingCodable")
var myName = T.customName()
return nil
}
struct Example1: Codable {}
struct Example2: Codable, MetadataProvidingCodable {
static func customName() -> String {
return "Example2"
}
}
let example1: Example1? = doWhatever()
let example2: Example2? = doWhatever()
// prints
// doWhatever: Codable
// doWhatever: Codable & MetadataProvidingCodable

Why does a property observer run when a member of the existing value is changed?

Please consider this Swift code. I have a class which wraps an instance of another class. When I set a property on the held value, the wrapper class's property observer is run.
protocol MyProtocol {
var msgStr: String? { get set }
}
class MyClass: MyProtocol {
var msgStr: String? {
didSet {
print("In MyClass didSet")
}
}
}
class MyWrapperClass {
var myValue: MyProtocol! {
didSet {
print("In MyWrapperClass didSet")
}
}
}
let wrapperObj = MyWrapperClass()
wrapperObj.myValue = MyClass() // Line1
wrapperObj.myValue.msgStr = "Some other string" // Line2
The output of above code is:
In MyWrapperClass didSet
In MyClass didSet
In MyWrapperClass didSet
I know that didSet is called when the value of the variable changes.
So when above code at "Line1" executes I understand that "In MyWrapperClass didSet" is printed, and that is fine.
Next when Line2 executes, I expect "In MyClass didSet" to be printed which correctly happens, but I am not sure why "In MyWrapperClass didSet" is printed, as the property myValue is not changed. Can someone explain why?
Swift needs to treat the mutation of myValue.msgStr as having value semantics; meaning that a property observer on myValue needs to be triggered. This is because:
myValue is a protocol-typed property (which also just happens to be optional). This protocol isn't class-bound, so conforming types could be both value and reference types.
The myStr property requirement has an implicitly mutating setter because of both (1) and the fact that it hasn't been marked nonmutating. Therefore the protocol-typed value may well be mutated on mutating though its myStr requirement.
Consider that the protocol could have been adopted by a value type:
struct S : MyProtocol {
var msgStr: String?
}
In which case a mutation of msgStr is semantically equivalent to re-assigning an S value with the mutated value of msgStr back to myValue (see this Q&A for more info).
Or a default implementation could have re-assigned to self:
protocol MyProtocol {
init()
var msgStr: String? { get set }
}
extension MyProtocol {
var msgStr: String? {
get { return nil }
set { self = type(of: self).init() }
}
}
class MyClass : MyProtocol {
required init() {}
}
class MyWrapperClass {
// consider writing an initialiser rather than using an IUO as a workaround.
var myValue: MyProtocol! {
didSet {
print("In MyWrapperClass didSet")
}
}
}
In which case the mutation of myValue.myStr re-assigns a completely new instance to myValue.
If MyProtocol had been class-bound:
protocol MyProtocol : class {
var msgStr: String? { get set }
}
or if the msgStr requirement had specified that the setter must be non-mutating:
protocol MyProtocol {
var msgStr: String? { get nonmutating set }
}
then Swift would treat the mutation of myValue.msgStr as having reference semantics; that is, a property observer on myValue won't get triggered.
This is because Swift knows that the property value cannot change:
In the first case, only classes can conform, and property setters on classes cannot mutate self (as this is an immutable reference to the instance).
In the second case, the msgStr requirement can only either be satisfied by a property in a class (and such properties don't mutate the reference) or by a computed property in a value type where the setter is non-mutating (and must therefore have reference semantics).
Alternatively, if myValue had just been typed as MyClass!, you would also get reference semantics because Swift knows you're dealing with a class:
class MyClass {
var msgStr: String? {
didSet {
print("In MyClass didSet")
}
}
}
class MyWrapperClass {
var myValue: MyClass! {
didSet {
print("In MyWrapperClass didSet")
}
}
}
let wrapperObj = MyWrapperClass()
wrapperObj.myValue = MyClass() // Line1
wrapperObj.myValue.msgStr = "Some other string" // Line2
// In MyWrapperClass didSet
// In MyClass didSet
I suspect this is happening because your protocol is not specified to be a class protocol. Because of that, MyProtocol could be a struct and thus didSet is triggered when the object is changed in any way (which is correct behavior for a value type).
If you change your protocol to:
protocol MyProtocol: class {
var msgStr: String? { get set }
}
then Swift knows that MyProtocol represents a reference type, so didSet will not be called for myValue in MyWrapperClass when the string is set.
It looks like a bug, see: https://bugs.swift.org/browse/SR-239
Also workaround is predefining variable, like:
protocol MyProtocol {
var msgStr: String? { get set }
}
class MyClass: MyProtocol {
var msgStr: String? {
didSet {
print("In MyClass didSet")
}
}
}
class MyWrapperClass {
var myValue: MyProtocol! {
didSet {
print("In MyWrapperClass didSet")
}
}
}
let wrapperObj = MyWrapperClass()
wrapperObj.myValue = MyClass() // Line1
var obj = wrapperObj.myValue!
obj.msgStr = "Some other string" // Line2

using setValue(value, forKey) for generic property

I have the following sample code:
class A<T> : NSObject {
var value: T? = nil
}
class B<T> : NSObject {
private var _value: T? = nil
var value: AnyObject?{
get{
return _value as? AnyObject
}
set{
_value = newValue as? T
}
}
}
var obj = B<Int>()
print(obj.value) // "nil"
obj.setValue(5, forKey: "value")
print(obj.value!) // "5"
This works fine if I use B class. However, my target is to use smaller class A which I can't use because of the exception thrown on the setValue function:
this class is not key value coding-compliant for the key value
Is there is a way to pass value to the generic property in the setValue function? And if it is official restriction, where I can read about this?

How to construct convenience init? in Swift [duplicate]

With the following code I try to define a simple model class and it's failable initializer, which takes a (json-) dictionary as parameter. The initializer should return nil if the user name is not defined in the original json.
1.
Why doesn't the code compile? The error message says:
All stored properties of a class instance must be initialized before returning nil from an initializer.
That doesn't make sense. Why should I initialize those properties when I plan to return nil?
2.
Is my approach the right one or would there be other ideas or common patterns to achieve my goal?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
That doesn't make sense. Why should I initialize those properties when
I plan to return nil?
According to Chris Lattner this is a bug. Here is what he says:
This is an implementation limitation in the swift 1.1 compiler,
documented in the release notes. The compiler is currently unable to
destroy partially initialized classes in all cases, so it disallows
formation of a situation where it would have to. We consider this a
bug to be fixed in future releases, not a feature.
Source
EDIT:
So swift is now open source and according to this changelog it is fixed now in snapshots of swift 2.2
Designated class initializers declared as failable or throwing may now return nil or throw an error, respectively, before the object has been fully initialized.
Update: From the Swift 2.2 Change Log (released March 21, 2016):
Designated class initializers declared as failable or throwing may now return nil or throw an error, respectively, before the object has been fully initialized.
For Swift 2.1 and earlier:
According to Apple's documentation (and your compiler error), a class must initialize all its stored properties before returning nil from a failable initializer:
For classes, however, a failable initializer can trigger an
initialization failure only after all stored properties introduced by
that class have been set to an initial value and any initializer
delegation has taken place.
Note: It actually works fine for structures and enumerations, just not classes.
The suggested way to handle stored properties that can't be initialized before the initializer fails is to declare them as implicitly unwrapped optionals.
Example from the docs:
class Product {
let name: String!
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
In the example above, the name property of the Product class is
defined as having an implicitly unwrapped optional string type
(String!). Because it is of an optional type, this means that the name
property has a default value of nil before it is assigned a specific
value during initialization. This default value of nil in turn means
that all of the properties introduced by the Product class have a
valid initial value. As a result, the failable initializer for Product
can trigger an initialization failure at the start of the initializer
if it is passed an empty string, before assigning a specific value to
the name property within the initializer.
In your case, however, simply defining userName as a String! does not fix the compile error because you still need to worry about initializing the properties on your base class, NSObject. Luckily, with userName defined as a String!, you can actually call super.init() before you return nil which will init your NSObject base class and fix the compile error.
class User: NSObject {
let userName: String!
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
super.init()
if let value = dictionary["user_name"] as? String {
self.userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
self.isSuperUser = value
}
self.someDetails = dictionary["some_details"] as? Array
}
}
I accept that Mike S's answer is Apple's recommendation, but I don't think it's best practice. The whole point of a strong type system is to move runtime errors to compile time. This "solution" defeats that purpose. IMHO, better would be to go ahead and initialize the username to "" and then check it after the super.init(). If blank userNames are allowed, then set a flag.
class User: NSObject {
let userName: String = ""
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: [String: AnyObject]) {
if let user_name = dictionary["user_name"] as? String {
userName = user_name
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
if userName.isEmpty {
return nil
}
}
}
Another way to circumvent the limitation is to work with a class-functions to do the initialisation.
You might even want to move that function to an extension:
class User: NSObject {
let username: String
let isSuperUser: Bool
let someDetails: [String]?
init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
self.userName = userName
self.isSuperUser = isSuperUser
self.someDetails = someDetails
super.init()
}
}
extension User {
class func fromDictionary(dictionary: NSDictionary) -> User? {
if let username: String = dictionary["user_name"] as? String {
let isSuperUser = (dictionary["super_user"] as? Bool) ?? false
let someDetails = dictionary["some_details"] as? [String]
return User(username: username, isSuperUser: isSuperUser, someDetails: someDetails)
}
return nil
}
}
Using it would become:
if let user = User.fromDictionary(someDict) {
// Party hard
}
Although Swift 2.2 has been released and you no longer have to fully initialize the object before failing the initializer, you need to hold your horses until https://bugs.swift.org/browse/SR-704 is fixed.
I found out this can be done in Swift 1.2
There are some conditions:
Required properties should be declared as implicitly unwrapped optionals
Assign a value to your required properties exactly once. This value may be nil.
Then call super.init() if your class is inheriting from another class.
After all your required properties have been assigned a value, check if their value is as expected. If not, return nil.
Example:
class ClassName: NSObject {
let property: String!
init?(propertyValue: String?) {
self.property = propertyValue
super.init()
if self.property == nil {
return nil
}
}
}
A failable initializer for a value type (that is, a structure or
enumeration) can trigger an initialization failure at any point within
its initializer implementation
For classes, however, a failable initializer can trigger an
initialization failure only after all stored properties introduced by
that class have been set to an initial value and any initializer
delegation has taken place.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/sg/jEUH0.l
You can use convenience init:
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
self.userName = userName
self.isSuperUser = isSuperUser
self.someDetails = someDetails
}
convenience init? (dict: NSDictionary) {
guard let userName = dictionary["user_name"] as? String else { return nil }
guard let isSuperUser = dictionary["super_user"] as? Bool else { return nil }
guard let someDetails = dictionary["some_details"] as? [String] else { return nil }
self.init(userName: userName, isSuperUser: isSuperUser, someDetails: someDetails)
}
}

Get class name of object as string in Swift

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