2

I need to determine the dynamic type of my object in a method that is implemented in a super class. The super class is called BaseClient and DisplayClient inherits from it.

I only need the class name, not the package name. This is what I tried:

print("1", String(describing: type(of: self))) // DisplayClient
print("2", type(of: self))                     // DisplayClient
print("3", type(of: self).description())       // package.DisplayClient
print("4", "\(type(of: self))")                // DisplayClient

Why does

 type(of: self).description()

return package.DisplayClient while the others only return the class name? I wonder what is called internally when I use String(describing: type(of: self)). I would assume this does exactly what I do (call describing()).

Where can I find more info on how the strings get generated internally?

The docs say:

Use this initializer to convert an instance of any type to its preferred representation as a String instance. The initializer creates the string representation of instance in one of the following ways, depending on its protocol conformance:

  • If instance conforms to the TextOutputStreamable protocol, the result is obtained by calling instance.write(to: s) on an empty string s.
  • If instance conforms to the CustomStringConvertible protocol, the result is instance.description.
  • If instance conforms to the CustomDebugStringConvertible protocol, the result is instance.debugDescription.
  • An unspecified result is supplied automatically by the Swift standard library.

But type(of: self) does not even have a description attribute. It only has a description() method. Is this some special case that is handled differently by the compiler?

Simon Hessner
  • 1,757
  • 1
  • 22
  • 49

1 Answers1

3

If your class inherits from NSObject then type(of: self).description() invokes the NSObject.description() class method:

class func description() -> String

NSObject's implementation of this method simply prints the name of the class.

and it is not documented whether that includes the module name or not. If your class does not inherit from NSObject then there is no default description() method.

On the other hand,

print(String(describing: type(of: self))) // DisplayClient
print(type(of: self))                     // DisplayClient

both print the unqualified type name, and

print(String(reflecting: type(of: self))) // package.DisplayClient
debugPrint(type(of: self) )               // package.DisplayClient

both print the fully qualified type name, compare How to get a Swift type name as a string with its namespace (or framework name) and the Xcode 7 Release Notes:

Type names and enum cases now print and convert to String without qualification by default. debugPrint or String(reflecting:) can still be used to get fully qualified names.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I use String(describing: type(of: self)) now and it works for me. The only problem is that this returns some additional information for classes that are not public. Example: "(InitialState in _AF5C6D4A3B423A6F0735A7740F802E5A)" is returned for the file-private class InitialState. But as I only use this information for my console output (logging) it is no big problem If I change the class to public, only "InitialState" is returned (like expected) – Simon Hessner Jan 21 '18 at 18:01
  • related: https://stackoverflow.com/questions/48306011/swift-4-typeof-self-differs-when-using-private-fileprivate – Simon Hessner Jan 21 '18 at 18:05