你能在 Swift 中创建匿名内部类吗?

Posted

技术标签:

【中文标题】你能在 Swift 中创建匿名内部类吗?【英文标题】:Can you create anonymous inner classes in Swift? 【发布时间】:2014-08-11 15:43:47 【问题描述】:

我厌倦了通过扩展UIAlertViewDelegate 来将整个类声明为能够处理UIAlertView 点击。当我有多个可能的UIAlertViews 时,它开始感觉混乱和错误,并且必须区分在处理程序中单击了哪个。

我真正想要的是创建一个实现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 使用没有任何委托的闭包。但从学术的角度来看,这种模式还是很有趣的。

我根本不会使用匿名类。我只会创建一个可以分配为委托的类,并接受在发生某些事情时执行的闭包。

您甚至可以升级它以接受每种操作的闭包:onDismissonCancel 等。或者您甚至可以让此类生成警报视图,将其自身设置为委托。

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 中创建匿名内部类吗?的主要内容,如果未能解决你的问题,请参考以下文章

java内部类的匿名内部类

该如何理解匿名内部类的功能?

内部类和匿名内部类的用法

在 ruby​​ 中创建匿名类

java中,匿名内部类可以使用外部类的成员变量吗

请问JAVA中匿名内部类有啥用,举个例子,谢谢