lazy instantiation closures vs. just using methods - swift

I was following a Swift tutorial on closures and ran across this piece of code.
class HTMLEelement {
let name: String
let text: String
lazy var asHTML: () -> String = {
[weak self] in
guard let this = self else { return "" }
return "<\(this.name)> \(this.text) </\(this.name)>"
}
init(name:String, text: String) {
self.name = name
self.text = text
}
deinit {
print("HTMLELEMENT \(name) is being deallocated")
}
}
Why did they define the function asHTML like they did instead of just using a regular public method?

Without declaring var as lazy, you cannot use "self" during its initialization. I think this was the main reason to use lazy in your example.

Related

Is it possible to add an observer on struct variable in Swift?

I need to track the update in a variable of struct type.
Is it possible to add an observer on struct variable in Swift?
Example:
struct MyCustomStruct {
var error:Error?
var someVar:String?
}
class MyClass{
var myCustomStruct:MyCustomStruct?
}
I want to add an observer on myCustomStruct variable.
The standard Swift “property observers” (didSet and willSet) are designed to let a type observe changes to its own properties, but not for letting external objects add their own observers. And KVO, which does support external observers, is only for dynamic and #objc properties NSObject subclasses (as outlined in Using Key-Value Observing in Swift).
So, if you want to have an external object observe changes within a struct, as others have pointed out, you have to create your own observer mechanism using Swift didSet and the like. But rather than implementing that yourself, property by property, you can write a generic type to do this for you. E.g.,
struct Observable<T> {
typealias Observer = String
private var handlers: [Observer: (T) -> Void] = [:]
var value: T {
didSet {
handlers.forEach { $0.value(value) }
}
}
init(_ value: T) {
self.value = value
}
#discardableResult
mutating func observeNext(_ handler: #escaping (T) -> Void) -> Observer {
let key = UUID().uuidString as Observer
handlers[key] = handler
return key
}
mutating func remove(_ key: Observer) {
handlers.removeValue(forKey: key)
}
}
Then you can do things like:
struct Foo {
var i: Observable<Int>
var text: Observable<String>
init(i: Int, text: String) {
self.i = Observable(i)
self.text = Observable(text)
}
}
class MyClass {
var foo: Foo
init() {
foo = Foo(i: 0, text: "foo")
}
}
let object = MyClass()
object.foo.i.observeNext { [weak self] value in // the weak reference is really only needed if you reference self, but if you do, make sure to make it weak to avoid strong reference cycle
print("new value", value)
}
And then, when you update the property, for example like below, your observer handler closure will be called:
object.foo.i.value = 42
It’s worth noting that frameworks like Bond or RxSwift offer this sort of functionality, plus a lot more.
With variables you can use two default observers
willSet - represents moment before variable will be set with new value
didSet - represents moment when variable was set
Also in observer you can work with two values. With current variable in current state, and with constant depending on observer
struct Struct {
var variable: String {
willSet {
variable // before set
newValue // after set, immutable
}
didSet {
oldValue // before set, immutable
variable // after set
}
}
}
And the same you can do for any other stored property, so you can use it for struct variable in your class too
class Class {
var myStruct: Struct? {
didSet {
...
}
}
}
Also you can for example in did set observer of variable post notification with certain name
didSet {
NotificationCenter.default.post(name: Notification.Name("VariableSet"), object: nil)
}
and then you can add certain class as observer for notification with this name
class Class {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(variableSet), name: Notification.Name("VariableSet"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: Notification.Name("VariableSet"), object: nil)
}
#objc func variableSet() {
...
}
}
Try this, first create a struct with an action variable and when you create an object of the struct set the action parameter on the action you want. ex.
struct testStruct {
var action: (()->())?
var variable: String? {
didSet {
self.action?()
}
}
}
And inside your main code - main class
var testS = testStruct()
testS.action = {
print("Hello")
}
testS.variable = "Hi"
When you set the testS.variabe = "Hi" it will call the print("Hello")
struct MyCustomStruct {
var error:Error?
var someVar:String?
}
class MyClass{
var myCustomStruct:MyCustomStruct? {
didSet{
print("my coustomeSruct changed")
}
}
}
let aClass = MyClass()
aClass.myCustomStruct?.someVar = " test"
//prints:my coustomeSruct changed

Create member variable with closure in its constructor

I'm having the following code in my class:
// MARK: - Lifecycle
init() {
authenticationContext = AuthenticationContext()
synchronizationContext = SynchronizationContext()
employeesCoordinator = EmployeesCoordinator()
serverErrorObserver =
NotificationObserver(notification: serverErrorNotification,
block: handleServerError) // <- Error
}
// MARK: - Listeners
private let serverErrorObserver: NotificationObserver!
private lazy var handleServerError: NSError -> () = {
[unowned self] (error) in
// Currently means that the token is expired, so remove stored instance
self.handleAuthorizationDidExpired()
}
It looks legit, but I'm getting the following complier error:
Use of 'self' in property access 'handleServerError' before all stored
properties are initialized
If it would help, this is the source behind NotificationObserver:
class ValueWrapper<T> {
let value: T
init(_ value: T) { self.value = value }
}
// Notification
struct Notification<A> {
let name: String
}
// Global Functions
func publish<A>(note: Notification<A>, value: A) {
let userInfo = ["value": ValueWrapper(value)]
NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: nil, userInfo: userInfo)
}
//
class NotificationObserver {
let observer: NSObjectProtocol
init<A>(notification: Notification<A>, block aBlock: A -> ()) {
observer = NSNotificationCenter.defaultCenter().addObserverForName(notification.name, object: nil, queue: nil) { note in
let wrapper = note.userInfo?["value"] as? ValueWrapper<A>
if let value = wrapper?.value {
aBlock(value)
} else {
assert(false, "Couldn't understand user info")
}
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(observer)
}
}
// Global variables
let serverErrorNotification: Notification<NSError> = Notification(name: "ServerErrorNotification")
let synchronizationDidCompleteNotification: Notification<Int> = Notification(name: "SynchronizationDidCompleteNotification")
let authorizationDidCompleteNotification: Notification<Authorization> = Notification(name: "SynchronizationDidCompleteNotification")
You cannot call self until you have properly initialized the object using super.init()
if you have un-initialized let variables they should initialize before super.init() call.
so doing so you cannot call to self - closure calls to self
so you have to change let to var, then call super.init() before assigning closure
private let serverErrorObserver: NotificationObserver!
to
private var serverErrorObserver: NotificationObserver!
eg.
init() {
super.init()
authenticationContext = AuthenticationContext()
synchronizationContext = SynchronizationContext()
employeesCoordinator = EmployeesCoordinator()
serverErrorObserver =
NotificationObserver(notification: serverErrorNotification,
block: handleServerError) // <- Error
}
The problem is that you are accessing self in the init() in the following line:
self.handleAuthorizationDidExpired()
You can't do it until all of the stored properties are initialised. And the only property, which is not initialised yet in your case, is serverErrorObserver.
In order to fix it easily, you can mark this property in the following way:
private(set) var serverErrorObserver: NotificationObserver?
By marking it optional you tell the compiler that this property doesn't need to be initialised when the object is created.

Singleton in Swift

I've been trying to implement a singleton to be used as a cache for photos which I uploaded to my iOS app from the web. I've attached three variants in the code below. I tried to get variant 2 working but it is causing a compiler error which I do not understand and would like to get help on what am I doing wrong. Variant 1 does the caching but I do not like the use of a global variable. Variant 3 does not do the actual caching and I believe it is because I am getting a copy in the assignment to var ic = ...., is that correct?
Any feedback and insight will be greatly appreciated.
Thanks,
Zvi
import UIKit
private var imageCache: [String: UIImage?] = [String : UIImage?]()
class ImageCache {
class var imageCache: [String : UIImage?] {
struct Static {
static var instance: [String : UIImage?]?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = [String : UIImage?]()
}
return Static.instance!
}
}
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://images.apple.com/v/iphone-5s/gallery/a/images/download/photo_1.jpg")!)!)
//variant 1 - this code is working
imageCache["photo_1"] = imageView.image
NSLog(imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 2 - causing a compiler error on next line: '#lvalue $T7' is not identical to '(String, UIImage?)'
//ImageCache.imageCache["photo_1"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 3 - not doing the caching
//var ic = ImageCache.imageCache
//ic["photo_1)"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
}
}
The standard singleton pattern is:
final class Manager {
static let shared = Manager()
private init() { ... }
func foo() { ... }
}
And you'd use it like so:
Manager.shared.foo()
Credit to appzYourLife for pointing out that one should declare it final to make sure it's not accidentally subclassed as well as the use of the private access modifier for the initializer, to ensure you don't accidentally instantiate another instance. See https://stackoverflow.com/a/38793747/1271826.
So, returning to your image cache question, you would use this singleton pattern:
final class ImageCache {
static let shared = ImageCache()
/// Private image cache.
private var cache = [String: UIImage]()
// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
private init() { }
/// Subscript operator to retrieve and update cache
subscript(key: String) -> UIImage? {
get {
return cache[key]
}
set (newValue) {
cache[key] = newValue
}
}
}
Then you can:
ImageCache.shared["photo1"] = image
let image2 = ImageCache.shared["photo2"])
Or
let cache = ImageCache.shared
cache["photo1"] = image
let image2 = cache["photo2"]
Having shown a simplistic singleton cache implementation above, we should note that you probably want to (a) make it thread safe by using NSCache; and (b) respond to memory pressure. So, the actual implementation is something like the following in Swift 3:
final class ImageCache: NSCache<AnyObject, UIImage> {
static let shared = ImageCache()
/// Observer for `UIApplicationDidReceiveMemoryWarningNotification`.
private var memoryWarningObserver: NSObjectProtocol!
/// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
///
/// Add observer to purge cache upon memory pressure.
private override init() {
super.init()
memoryWarningObserver = NotificationCenter.default.addObserver(forName: .UIApplicationDidReceiveMemoryWarning, object: nil, queue: nil) { [weak self] notification in
self?.removeAllObjects()
}
}
/// The singleton will never be deallocated, but as a matter of defensive programming (in case this is
/// later refactored to not be a singleton), let's remove the observer if deallocated.
deinit {
NotificationCenter.default.removeObserver(memoryWarningObserver)
}
/// Subscript operation to retrieve and update
subscript(key: String) -> UIImage? {
get {
return object(forKey: key as AnyObject)
}
set (newValue) {
if let object = newValue {
setObject(object, forKey: key as AnyObject)
} else {
removeObject(forKey: key as AnyObject)
}
}
}
}
And you'd use it as follows:
ImageCache.shared["foo"] = image
And
let image = ImageCache.shared["foo"]
For Swift 2.3 example, see previous revision of this answer.
Swift 3:
class SomeClass
{
static let sharedInstance = SomeClass()
fileprivate override init() {
//This prevents others from using the default '()' initializer
super.init()
}
func sayHello()
{
print("Hello!")
}
}
Invoke some Method:
SomeClass.sharedInstance.sayHello() //--> "Hello"
Invoke some Method by creating a new class instance (fails):
SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers
Swift-5
To create a singleton class:
import UIKit
final class SharedData: NSObject {
static let sharedInstance = SharedData()
private override init() { }
func methodName() { }
}
To access
let sharedClass = SharedClass.sharedInstance
OR
SharedClass.sharedInstance.methodName()
Following are the two different approaches to create your singleton class in swift 2.0
Approach 1) This approach is Objective C implementation over swift.
import UIKit
class SomeManager: NSObject {
class var sharedInstance : SomeManager {
struct managerStruct {
static var onceToken : dispatch_once_t = 0
static var sharedObject : SomeManager? = nil
}
dispatch_once(&managerStruct.onceToken) { () -> Void in
managerStruct.sharedObject = SomeManager()
}
return managerStruct.sharedObject!
}
func someMethod(){
print("Some method call")
}
}
Approach 2) One line Singleton, Don't forget to implement the Private init (restrict usage of only singleton)
import UIKit
class SomeManager: NSObject {
static let sharedInstance = SomeManager()
private override init() {
}
func someMethod(){
print("Some method call")
}
}
Call the Singleton method like :
SomeManager.sharedInstance.someMethod()

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

Strong reference cycle for closures in Swift

I was going through the documentation (chapter on “Automatic Reference Counting” section “Strong Reference Cycles for Closures”) and I can't seem to figure out cases, when defining a class, in which I should keep a strong reference to self (the instance of that class) in a closure to a property.
Capture Lists seem always the best solution to avoid memory leaks, and I really can't think of any scenarios in which I should keep a strong reference cycle.
Here are the examples that the documentation gives:
class HTMLElement {
let name: String
let text: String?
// Without Capture List
#lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
class HTMLElement {
let name: String
let text: String?
// With Capture List
#lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
You need to keep a strong reference to self if you’re creating a closure to be executed by an object or function whose lifetime may not match self’s.
For example:
class A {
func do() {
dispatch_async(dispatch_get_global_queue(0, 0)) {
println("I printed \(self) some time in the future.")
}
}
}
var a : A? = A()
a.do()
a = nil // <<<
At the arrow the main function body will release its last reference to the newly created instance of A, but the dispatch queue needs to keep a hold on it until the closure is done executing.