你能在 Swift 中创建匿名内部类吗?
Posted
技术标签:
【中文标题】你能在 Swift 中创建匿名内部类吗?【英文标题】:Can you create anonymous inner classes in Swift? 【发布时间】:2014-08-11 15:43:47 【问题描述】:我厌倦了通过扩展UIAlertViewDelegate
来将整个类声明为能够处理UIAlertView
点击。当我有多个可能的UIAlertView
s 时,它开始感觉混乱和错误,并且必须区分在处理程序中单击了哪个。
我真正想要的是创建一个实现UIAlertViewDelegate
协议的对象,并在显示时将这个一次性对象提供给我的UIAlertView
。
我想要这样的东西:
let confirmDelegate = UIAlertViewDelegate()
func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int)
// Handle the click for my alertView
然后在显示警报时使用它:
let alertView = UIAlertView(title: "Confirm", message: "Are you sure?", delegate: confirmDelegate, cancelButtonTitle: "No", otherButtonTitles: "Yes")
alertView.show()
在不声明新类的情况下这可能吗?
我知道我可以这样做:
class ConfirmDelegate: UIAlertViewDelegate
func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int)
// ...
然后实例化一个ConfirmDelegate()
,但我只是想知道这是否可以作为单行类声明和实例化。
【问题讨论】:
我认为您的目标是 ios 7。但对于其他运行此系统并以 iOS 8 为目标的人。不要忘记基于块的新UIAlertController
类。
即使你能做到,你的代码显示的也不正确,因为 UIAlertView 的委托没有保留,一旦你的本地引用在函数结束时消失,委托将是解除分配。
@newacct 我不知道代表是弱引用(这就是你的意思?)。这可能是这种行为似乎不存在的原因。
@ChrisWagner 我需要这个才能在 IOS 7 上工作,是的,但我还在学习 IOS 开发,不知道 UIAlertController
,谢谢
这只是我发现 android 似乎做得更整洁的唯一一件事。虽然从目标/动作到块的逐渐切换似乎消除了这一点。
【参考方案1】:
正如@ChrisWagner 在他的评论中所说,您不需要在 iOS8 中执行任何这些操作,至少对于UIAlertView
,因为有一个新的UIAlertViewController
使用没有任何委托的闭包。但从学术的角度来看,这种模式还是很有趣的。
我根本不会使用匿名类。我只会创建一个可以分配为委托的类,并接受在发生某些事情时执行的闭包。
您甚至可以升级它以接受每种操作的闭包:onDismiss
、onCancel
等。或者您甚至可以让此类生成警报视图,将其自身设置为委托。
import UIKit
class AlertViewHandler: NSObject, UIAlertViewDelegate
typealias ButtonCallback = (buttonIndex: Int)->()
var onClick: ButtonCallback?
init(onClick: ButtonCallback?)
super.init()
self.onClick = onClick
func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int)
onClick?(buttonIndex: buttonIndex)
class ViewController: UIViewController
// apparently, UIAlertView does NOT retain it's delegate.
// So we have to keep it around with this instance var
// It'll be nice when all of UIKit is properly Swift-ified :(
var alertHandler: AlertViewHandler?
func doSoemthing()
alertHandler = AlertViewHandler( (clickedIndex: Int) in
println("clicked button \(clickedIndex)")
)
let alertView = UIAlertView(
title: "Test",
message: "OK",
delegate: alertHandler!,
cancelButtonTitle: "Cancel"
)
传递闭包应该减轻对匿名类的需求。至少对于最常见的情况。
【讨论】:
花哨的语法。这肯定更接近我正在寻找的东西。在typealias
行上,基本上是在声明一个接受Int
并且不返回任何内容的lambda?您传递给AlertViewHandler
构造函数的内容是满足lambda 合约的匿名函数的语法吗?我的术语和习语可能略有偏差。我将不得不阅读该语法。
不错的方法@AlexWayne,投票给你!但是,我很好奇,如果在分配时初始化 AlertViewHandler
这样会导致在 runloop 退出 doSomething
范围后释放该实例?它不需要是实例变量才能正确保留吗?
对于解除分配,alertView
应该保留分配给它的委托,并在完成后释放它。所以它应该坚持下去。但是,如果您想以其他方式引用该对象,则完全可以将其分配给实例变量。 编辑看来我错了!可能想先将其保存到实例变量中。 :(
还有相当多的库实现了这个概念并且应该与 Swift 一起工作。 cocoapods.org/?q=alert+block
@AlexWayne 可能使用对象关联并将对象直接连接到警报视图? developer.apple.com/library/mac/documentation/Cocoa/Reference/…(编辑:这是对 objc_setAssociatedObject 的引用;我不知道为什么我认为 Apple 的 html 会正常工作)【参考方案2】:
不幸的是,据我所知,不,您不能有效地创建匿名内部类。不过,您建议的语法在 IMO 中会非常好。
这是我试图获得接近你想要的东西的尝试,但它远没有那么干净。
import UIKit
class AlertViewDelegate: NSObject, UIAlertViewDelegate
func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int)
func alertView(alertView: UIAlertView!, didDismissWithButtonIndex buttonIndex: Int)
func alertView(alertView: UIAlertView!, willDismissWithButtonIndex buttonIndex: Int)
func alertViewCancel(alertView: UIAlertView!)
func alertViewShouldEnableFirstOtherButton(alertView: UIAlertView!) -> Bool
return true
class ViewController: UIViewController
var confirmDelegate: AlertViewDelegate?
func doSoemthing()
confirmDelegate =
class ConfirmDelegate: AlertViewDelegate
override func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int)
println("clicked button \(buttonIndex)")
return ConfirmDelegate()
()
let alertView = UIAlertView(title: "Test", message: "OK", delegate: confirmDelegate, cancelButtonTitle: "Cancel")
【讨论】:
我明白了,所以您创建了一个实现协议的具体类,然后您可以选择性地覆盖您想要的功能。不幸的是,它的代码要多得多,但在某些情况下可能是一种有用的策略。 是的,我个人更喜欢使用闭包的解决方案。就像 Alex 和UIAlertView
上的许多第三方 Objective-C 包装器一样,它们使它们基于块。
我似乎无法编译这样的示例 - 函数内部块内的内部类。你还能在 Swift 1.0 中编译它吗?以上是关于你能在 Swift 中创建匿名内部类吗?的主要内容,如果未能解决你的问题,请参考以下文章