Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestions #1

Open
DanielSwift1992 opened this issue Jan 13, 2019 · 2 comments
Open

Suggestions #1

DanielSwift1992 opened this issue Jan 13, 2019 · 2 comments

Comments

@DanielSwift1992
Copy link

DanielSwift1992 commented Jan 13, 2019

#45 Getting rid of overabundant [weak self] and guard

Just a little bit another way with the same example

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

postfix operator ~
public postfix func ~ <T>(value: T) -> T.Type {
    return T.self
}

extension NSObjectProtocol {
    func weak<T>(_ closure: @escaping (Self) -> (T) -> Void) -> (T) -> Void {
        return { [weak self] in
            guard let self = self else { return }
            return closure(self)($0)
        }
    }
}

class Producer: NSObject {
    
    deinit {
        print("deinit Producer")
    }
    
    private var handler: (Int) -> Void = { _ in }
    
    func register(handler: @escaping (Int) -> Void) {
        self.handler = handler
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { self.handler(42) })
    }
}

class Consumer: NSObject {
    
    deinit {
        print("deinit Consumer")
    }
    
    let producer = Producer()
    
    func consume() {
        producer.register(handler: weak(self~ .handle))
    }
    
    private func handle(_ result: Int) {
        print("🎉 \(result)")
    }
}

var consumer: Consumer? = Consumer()

consumer?.consume()

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: { consumer = nil })

// This code prints:
// 🎉 42
// deinit Consumer
// deinit Producer

However sometimes you need function to return value and weak will not work. You might want to use unowned:

extension NSObjectProtocol {
    func unowned<T, U>(_ closure: @escaping (Self) -> (T) -> U) -> (T) -> U {
        return { [ unowned self] in
            return closure(self)($0)
        }
    }
}

#07 Implementing the builder pattern with keypaths

Not using keyPath allows to call functions:

import UIKit

extension NSObjectProtocol {
    @discardableResult
    func apply(_ closure: (Self) -> () ) -> Self {
    { closure(self) }()
        return self
    }
}

let view = UIView()

let label = UILabel().apply {
    $0.textColor = .red
    $0.text = "Foo \n Foo"
    $0.textAlignment = .right
    $0.layer.cornerRadius = 5
    
    $0.sizeToFit()
}

view.addSubview(label)

It is safe because it nonescaping closure.

@vincent-pradeilles
Copy link
Owner

Hello, thank you for those suggestions!

I understand that the operator ~ can have value in the context of a project. However, custom operators are a controversial topic, so I wouldn't advise its use in the general case.
But I feel that it could alternatively implemented as a computed property on NSObject, and you'd get to use it the same way than the operator.

The apply function is indeed interesting! If I remember well, I think it's actually part of the standard library in Kotlin 🙂

@DanielSwift1992
Copy link
Author

DanielSwift1992 commented Feb 11, 2019

Yes, but unfortunately in swift you can't get rid of "$0". At list I do not know how to do that =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants