Is there any way to get the following working in Swift 3?
在Swift 3中有什么方法可以让以下内容发挥作用吗?
let button = UIButton().apply {
$0.setImage(UIImage(named: "UserLocation"), for: .normal)
$0.addTarget(self, action: #selector(focusUserLocation),
for: .touchUpInside)
$0.translatesAutoresizingMaskIntoConstraints = false
$0.backgroundColor = UIColor.black.withAlphaComponent(0.5)
$0.layer.cornerRadius = 5
}
The apply<T>
function should take a closure of type (T)->Void
, run it passing self
into it, and then simply return self
.
apply
Another option would be to use an operator for this like "=>
" (borrowed the idea from Kotlin and Xtend languages).
另一种选择是使用一个操作符,例如“=>”(借用了Kotlin和Xtend语言的概念)。
Tried to do extension of NSObject
like this:
尝试扩展NSObject:
extension NSObject {
func apply<T>(_ block: (T)->Void) -> T
{
block(self as! T)
return self as! T
}
}
But it requires explicit declaration of the parameter type in closure:
但需要在闭包中明确地声明参数类型:
let button = UIButton().apply { (it: UIButton) in
it.setImage(UIImage(named: "UserLocation"), for: .normal)
it.addTarget(self, action: #selector(focusUserLocation),
for: .touchUpInside)
...
This is not convenient and makes the whole idea not worth the effort. The type is already specified at object creation and it should be possible not to repeat it explicitly.
这是不方便的,使整个想法不值得努力。在对象创建时已经指定了类型,应该可以不显式地重复它。
Thanks!
谢谢!
5 个解决方案
#1
8
The HasApply protocol
First of all lets define the HasApply
protocol
首先让我们定义HasApply协议
protocol HasApply { }
and related extension
和相关扩展
extension HasApply {
func apply(closure:(Self) -> ()) -> Self {
closure(self)
return self
}
}
Next let make NSObject
conform to HasApply
.
接下来让NSObject符合HasApply。
extension NSObject: HasApply { }
That's it
Let's test it
让我们做个测试
let button = UIButton().apply {
$0.titleLabel?.text = "Tap me"
}
print(button.titleLabel?.text) // Optional("Tap me")
Considerations
I wouldn't use
NSObject
(it's part of the Objective-C way of doing things and I assume it will be removed at some point in the future). I would prefer something likeUIView
instead.我不会使用NSObject(它是Objective-C做事方式的一部分,我假设将来某个时候它会被删除)。我更喜欢UIView。
extension UIView: HasApply { }
#2
4
I had the same issue and ended up solving it with an operator:
我遇到了同样的问题,最后我找到了一个操作员:
infix operator <-< : AssignmentPrecedence
func <-<<T:AnyObject>(left:T, right:(T)->()) -> T
{
right(left)
return left
}
let myObject = UIButton() <-< { $0.isHidden = false }
#3
2
There's a very good and simple Cocoapods library available called Then
that does exactly that. Only that it uses then
instead of apply
. Simply import Then
and then you can do as the OP asked for:
有一个非常好的简单的可可粉库,叫做Then,它就是这么做的。只是它使用而不是应用。简单导入,然后你可以按照OP要求做:
import Then
myObject.then {
$0.objectMethod()
}
let label = UILabel().then {
$0.color = ...
}
Here's how the protocol is implemented: https://github.com/devxoul/Then/blob/master/Sources/Then.swift
协议的实现方式如下:https://github.com/devxoul/Then/blob/master/Sources/Then.swift
extension Then where Self: AnyObject {
public func then(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
#4
0
Alain has a good answer if you're not allergic to custom operators. If you'd rather not use those, the best alternative I could come up with was:
阿兰有一个很好的答案如果你不讨厌定制操作符。如果你不想用这些,我能想到的最好的选择是:
@discardableResult func apply<T>(_ it:T, f:(T)->()) -> T {
f(it)
return it
}
which then allows you to use:
然后允许您使用:
let button = apply(UIButton()) { $0.setTitleText("Button") }
It's not quite the same, but works out pretty well in general and has the advantage that T is completely unrestrained. It's an obviously contrived example, but:
它不是完全相同的,但总的来说效果很好,它的优点是T是完全不受限制的。这显然是人为的例子,但是:
func apply<T,R>(_ it:T, f:(T)->R) -> R {
return f(it)
}
even allows:
甚至允许:
print("\(apply(32) { $0 + 4 })")
#5
-1
This is example Generic With Protocol And Extension. I wish you to help you
这是具有协议和扩展的通用示例。我希望你能帮助你
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }}
class Stack<S>: Container {
// original Stack<T> implementation
var items = [S]()
func push(item: S) {
items.append(item)}
func pop() -> S {
return items.removeLast()
}
// conformance to the Container protocol
func append(item: S) {
self.push(item: item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> S {
return items[i]
}}
extension Stack {
var topItem: S? {
return items.isEmpty ? nil : items[items.count - 1]
}}
var stringStack = Stack<String>()
var intStack = Stack<Int>()
#1
8
The HasApply protocol
First of all lets define the HasApply
protocol
首先让我们定义HasApply协议
protocol HasApply { }
and related extension
和相关扩展
extension HasApply {
func apply(closure:(Self) -> ()) -> Self {
closure(self)
return self
}
}
Next let make NSObject
conform to HasApply
.
接下来让NSObject符合HasApply。
extension NSObject: HasApply { }
That's it
Let's test it
让我们做个测试
let button = UIButton().apply {
$0.titleLabel?.text = "Tap me"
}
print(button.titleLabel?.text) // Optional("Tap me")
Considerations
I wouldn't use
NSObject
(it's part of the Objective-C way of doing things and I assume it will be removed at some point in the future). I would prefer something likeUIView
instead.我不会使用NSObject(它是Objective-C做事方式的一部分,我假设将来某个时候它会被删除)。我更喜欢UIView。
extension UIView: HasApply { }
#2
4
I had the same issue and ended up solving it with an operator:
我遇到了同样的问题,最后我找到了一个操作员:
infix operator <-< : AssignmentPrecedence
func <-<<T:AnyObject>(left:T, right:(T)->()) -> T
{
right(left)
return left
}
let myObject = UIButton() <-< { $0.isHidden = false }
#3
2
There's a very good and simple Cocoapods library available called Then
that does exactly that. Only that it uses then
instead of apply
. Simply import Then
and then you can do as the OP asked for:
有一个非常好的简单的可可粉库,叫做Then,它就是这么做的。只是它使用而不是应用。简单导入,然后你可以按照OP要求做:
import Then
myObject.then {
$0.objectMethod()
}
let label = UILabel().then {
$0.color = ...
}
Here's how the protocol is implemented: https://github.com/devxoul/Then/blob/master/Sources/Then.swift
协议的实现方式如下:https://github.com/devxoul/Then/blob/master/Sources/Then.swift
extension Then where Self: AnyObject {
public func then(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
#4
0
Alain has a good answer if you're not allergic to custom operators. If you'd rather not use those, the best alternative I could come up with was:
阿兰有一个很好的答案如果你不讨厌定制操作符。如果你不想用这些,我能想到的最好的选择是:
@discardableResult func apply<T>(_ it:T, f:(T)->()) -> T {
f(it)
return it
}
which then allows you to use:
然后允许您使用:
let button = apply(UIButton()) { $0.setTitleText("Button") }
It's not quite the same, but works out pretty well in general and has the advantage that T is completely unrestrained. It's an obviously contrived example, but:
它不是完全相同的,但总的来说效果很好,它的优点是T是完全不受限制的。这显然是人为的例子,但是:
func apply<T,R>(_ it:T, f:(T)->R) -> R {
return f(it)
}
even allows:
甚至允许:
print("\(apply(32) { $0 + 4 })")
#5
-1
This is example Generic With Protocol And Extension. I wish you to help you
这是具有协议和扩展的通用示例。我希望你能帮助你
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }}
class Stack<S>: Container {
// original Stack<T> implementation
var items = [S]()
func push(item: S) {
items.append(item)}
func pop() -> S {
return items.removeLast()
}
// conformance to the Container protocol
func append(item: S) {
self.push(item: item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> S {
return items[i]
}}
extension Stack {
var topItem: S? {
return items.isEmpty ? nil : items[items.count - 1]
}}
var stringStack = Stack<String>()
var intStack = Stack<Int>()