5

在 javascript 中,我们经常使用 IIFE。就像是

(function() {
    ...do stuff to avoid dirtying scope.
}());

Swift 中有闭包,函数是第一类对象。我的问题是:Swift 中是否有等效的 IIFE?

4

6 回答 6

12

这里接受的答案是误导性的——有一种更简单、更优雅的方式来创建立即调用的闭包表达式 (IICE)。

有关语法的所有细节和差异,请参阅Apple Swift 文档以了解闭包。对于一个简单的演示,请参见:

let dateString: NSString = { date in
  let timestampFormatter = NSDateFormatter()

  timestampFormatter.dateStyle = .MediumStyle
  timestampFormatter.timeStyle = .MediumStyle

  return timestampFormatter.stringFromDate(date)
}(NSDate())

在此处输入图像描述

于 2015-08-09T00:46:05.223 回答
4

您可以使用闭包实现类似的效果,当然:

func iife( f : () -> () ) {
 f()
}

然后说

iffe { 
// my code here
}

如果你真正需要的只是一个作用域,而 Swift 不支持使用 {..} 作为“作用域运算符”,你总是可以这样做

if 1 == 1 {
// oh, look, a scope :-)
}

作为实现相同效果的不那么花哨的方式。如果您尝试使用 RAII 模式,则需要依靠 ARC 为您清理,或者使用闭包

if true {
    // should also work instead of if 1 == 1
}
于 2014-06-04T17:06:17.813 回答
4

这是 Swift 立即调用闭包表达式 (IICE) 的另一个示例——我将其发音为“Icky”(向 JavaScript 的 IIFE 致敬,发音为“Iffy”——http: //benalman.com/news/2010/11 /立即调用函数表达式/

var player:AVAudioPlayer = {
        let path = Bundle.main.path(forResource: "sound1", ofType: "mp3")!
        let url = NSURL(fileURLWithPath: path)
        let p = try! AVAudioPlayer(contentsOf: url as URL)
        p.volume = 0.3
        p.prepareToPlay()
        return p
    }()

如果你使用lazy修饰符,你就可以访问self.

来自 Swift 语言指南:“当属性的初始值依赖于外部因素时,延迟属性很有用,这些因素的值在实例初始化完成后才知道。当属性的初始值需要复杂时,延迟属性也很有用或计算量大的设置,除非需要,否则不应执行。”

let startVolume:Float = 0.3
lazy var player:AVAudioPlayer = {
       let path = Bundle.main.path(forResource: "sound1", ofType: "mp3")!
       let url = NSURL(fileURLWithPath: path)
       let p = try! AVAudioPlayer(contentsOf: url as URL)
       p.volume = self.startVolume
       p.prepareToPlay()
       return p
  }()

另请参阅 Swift 语言指南中的“使用闭包或函数设置默认属性值”。

于 2017-01-16T23:12:12.383 回答
0

当我想要一次性执行代码来初始化属性时,我发现了立即调用闭包的用途。例如:

class MyClass {
    //One time initialization of managedObjectContext property
    lazy var managedObjectContext: NSManagedObjectContext = { () -> NSManagedObjectContext in
        let context = NSManagedObjectContext()
        //do all the initial setup, etc...
        return context
    }()

    //more stuff...
}

还有其他方法可以实现相同的目标,但我发现这是一个不错的模式。

于 2015-05-31T05:12:12.600 回答
0

您可以使用内置do {}而无需catch

do {
  // local scope
  let x = 10
  print(x)
}

// global scope
let x = "string"
print(x)
于 2016-12-14T10:51:12.833 回答
0

这个怎么样?

({
    /* Code here */
}()) == ()

或这个?

({
    print("hi")
}()).self

还是来自 JS?

({
    print("hi")
}())
于 2020-12-21T21:55:49.070 回答