如何处理UIAlertAction的闭包参数

3

我一直在尝试创建一个带有处理程序的UIAlertAtion。我阅读了这个问题的答案,知道如何做。

我的问题只涉及其中的闭包部分。

1) 我知道可以写:{alert in println("Foo")}或者{_ in println("Foo")},但是我不能{println("Foo")}。在这里的评论中解释了这是因为你需要处理参数操作

这是否意味着,由于处理程序的类型是(UIAlertAction) -> Void),我必须始终捕获传递的alertAction?


2) 我也阅读了这个,答案基本上是说您可以将函数作为参数传递,但是该函数应该接受类型为UIAlertAction -> Void的内容,我写了:

private func anything(action : UIAlertAction) {
    print("hello")
}

然后我将我的alertaction编写为如下:

let anotherAction = UIAlertAction(title: "hi", style: UIAlertActionStyle.Default,
 handler: anything(action)) // error: Use of unresolved identifier 'action'

我不明白为什么会出现这个错误。


3) 在评论中还提到:但是除此之外,在swift中你不需要写UIAlertActionStyle.Default。.Default也可以工作

我尝试着不使用样式,以便默认为.Default

let sendLogAction = UIAlertAction(title: "Log") { action in print("goodbye")}

但是我遇到了以下错误:

'(title: String, (_) -> ())'(也就是 '(title: String, _ -> ())')无法转换为 '(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)?)'(也就是 '(title: Optional, style: UIAlertActionStyle, handler: Optional ()>)),元组的元素数量不同


4) 同时阅读这个答案。我不明白为什么我们需要传递 alert,这没有意义。好像我们已经定义了它的类型,我们不知道 alert 的类型是什么吗?!有人能解释一下在一般情况下传递操作本身会有什么用处吗?我的意思是我们能做些什么?


我知道这写成了 4 个问题,但我认为这实际上只是一个基础性问题。我在工程中广泛地阅读、使用闭包/完成处理程序,并在 playground 中进行了测试,但我仍然感到困惑。


#4 没有意义。你指的是哪个 alert - rmaddy
@rmaddy switch action.style... 他正在切换警报,但他不是已经定义了:style: .Default吗? - mfaani
他没有切换 alert。他正在切换 action.style。无论如何,那个 switch 语句只是一个例子。但这毫无意义。在实际代码中,没有人会这样做,因为你已经知道你设置了什么样式。 - rmaddy
@rmaddy 是的,我使用了错误的措辞,因为有时候我看到人们写action in,有时候是alert in,但它们并没有任何区别...还是没有意义。所以对于我的第4个问题,我想要一个很好的例子来展示被捕获的action的用途。 - mfaani
3个回答

3
  1. 是的,你必须始终处理这个参数。它是签名的一部分,不能被忽略。此外,Swift有一个特殊的语法,能够省略handler参数,因为它是最后一个参数,并且它是一个闭包参数。

  2. anything(action)更改为anything,就像你链接的示例一样。

  3. 你误解了。他们并没有说你可以省略style参数。他们说的是您可以从UIAlertActionStyle.Default中省略UIAlertActionStyle,这意味着您只需要将.Default作为style参数的参数传递即可。

  4. 你想要一个handler参数有用的示例。实际上并没有太多用处。唯一的属性是标题、风格和是否启用。后者是无意义的,因为如果调用了handler,则知道它是启用的。唯一可能的用途是如果标题或样式需要在处理程序中使用,并且它们在创建警报操作时没有硬编码。通过在处理程序中访问标题或样式属性,您可以轻松访问创建操作时使用的实际值。


  1. drop 是指尾随闭包吗?
  2. 哈!我没有在示例中看到上面的那一行。虽然这样做需要 self.anything,但我需要避免内存循环。
  3. 哈!
  4. 例如,您的意思是标题是动态从服务器获取的,可能是成功或失败,然后闭包的操作会根据标题而改变?
- mfaani
1
  1. 你可能有一系列动态按钮,因此标题不是硬编码的。然后处理程序可能需要将所选标题传递给其他方法调用。这只是一个可能的例子。
- rmaddy
关于需要使用self引用任何内容的问题。我理解对于属性这样做的必要性,但我不理解对于函数这样做的必要性。你能解释一下吗? - mfaani
那是完全不同的讨论。我建议您在确保它不是重复问题后,发布一个新的特定于该问题的问题。 - rmaddy

1

rmaddy的答案已经足够,但作为提问者 :) 我发现了我的问题的根本原因:

我对参数处理程序的理解不足,处理程序的类型是:(UIAlertAction) -> Void)? 即闭包/函数。

处理程序只期望函数名称,一旦您提供该函数,它将填充该函数本身的输入。

anything作为处理程序即可,即函数名称。

UIAlertAction的内部实现有一些行,例如handler(action),它将使用anything,它的类型为(UIAlertAction) -> Void)?,注入传递给它的action,最终执行anything(action)

话虽如此,您的anything(input: UIAlertAction)应该做一些有意义的事情。(已在评论中与rmaddy讨论过)


另一种解决方案是不提供函数,而是在尾随闭包中使用捕获的操作并进行任何您想要做的操作。
let retryAction = UIAlertAction(title: returnTitle(), style: UIAlertActionStyle.Default) { action in
switch action.title {
        case "OK":
        okFunc()
        case "cancel":
        cancelFunc()
        default:
        defaultFunc()
        }
      }

这种切换只有在代码是动态的情况下才有价值,否则对于已知值的图块切换没有附加价值。

0
1.

UIAlerActioninit方法定义接受3个参数,最后一个参数是(UIAlertAction -> Void)?,意味着你可以使用一个“无名”函数(也称为闭包)或者nil(通过可选符号?指定)。如果你选择不指定最后一个参数,你可以像这样创建UIAlertController

alert.addAction(UIAlertAction(title: "test", style: .default, handler: nil))

但是,如果你想指定最后一个参数(非nil),那么你必须提供一个接受UIAlertAction作为参数并返回Void的闭包。根据你的链接,他只是简单地使用了他已经创建的alert常量。

回答你的问题这是否意味着…,答案是是的,因为第三个参数的定义是:(UIAlertAction) -> Void)?

2.

你得到错误是因为你传递了参数(action)。试试用

anotherAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: anything)

然后你应该不会出错。

3.

UIAlertAction只有(我相信)一个初始化方法,所以你需要提供所有三个参数来创建它。参见我在1)中的答案关于style: .default的部分。这是一种调用Swift枚举的新方式。顺便说一下,所有的枚举都必须小写,所以是.default而不是.Default

alert.addAction(UIAlertAction(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void))

4.

正如你从链接的答案中看到的,你可以使用常量alertUIAlertAction)对其进行任何操作,比如检查样式并执行一些操作。

func anything(alert: UIAlertAction!) {
  print("somehandler")
  switch alert.title {
  case "OK"?:
    print("title is OK")
  default:
    print("title is not OK")
  }
}

  1. 好的
  2. 这和我写的一样,但还是不对。
  3. 正确的
  4. 我不明白你在那里的意思。
- mfaani
请查看以下修改后的内容:2)(我忘记在handler: anything之后删除(action))和4)是我指的在anything函数中使用alert做一些事情。 - Ohmy
常量 'action' 是什么意思? - mfaani
看到您添加的链接,此人创建了一个常量let alert = UIAlertViewController(.... - Ohmy
没有任何链接提到“常量”,如果您能分享一下,我会很感激。如果您指的是let中的常量,那么您回答中使用的常量与此非常不相关。使用let还是var有什么区别吗?而且您在谈论被捕获的上下文中的操作。所以我很困惑,为什么您在闭包之前提到它。从您的答案中删除它并不会使您的答案变得不那么有用。 - mfaani
@Honey:“let”定义是常量,即分配后不能更改。您在第一点下的第一个参考链接到一个定义了“let action”的文章,即“action”是一个常量。 - Yohst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接