在易错初始值设定器中赋值让variables1.2

我有一个错误的初始值设定项,而不是一个实例方法,但一个初始值设定项。 更新到1.2后,当我尝试在初始化程序中分配一个let属性时,我收到以下错误Cannot assign to 'aspectRatio' in self 。 我的代码如下:

 import Foundation public struct MediaItem { public let url: NSURL! public let aspectRatio: Double public var description: String { return (url.absoluteString ?? "no url") + " (aspect ratio = \(aspectRatio))" } // MARK: - Private Implementation init?(data: NSDictionary?) { var valid = false if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString { if let url = NSURL(string: urlString as String) { self.url = url let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber if h != nil && w != nil && h?.doubleValue != 0 { aspectRatio = w!.doubleValue / h!.doubleValue valid = true } } } if !valid { return nil } } struct TwitterKey { static let MediaURL = "media_url_https" static let Width = "sizes.small.w" static let Height = "sizes.small.h" } } 

我的问题是我该如何解决这个问题?

Swift 1.2已经封闭了一个漏洞,

新的规则是一个let常量必须在使用之前初始化(如var),并且它只能被初始化,在初始化之后不会被重新分配或者变异。

这个规则正是你想要违反的。 aspectRatio是一个let属性,你已经在它的声明中给了它一个值

 public let aspectRatio: Double = 0 

因此,在我们到达初始化器之前, aspectRatio的初始值为0.这是它唯一可以拥有的值。 新的规则意味着你永远不能指定aspectRatio即使在初始化器中也是如此

解决scheme是(而且这总是正确的方法):在它的声明中赋值:

 public let aspectRatio: Double 

现在,在初始化器中,将其赋值为0 将它赋值给w!.doubleValue / h!.doubleValue 。 换句话说,在初始化器中照顾每一个可能性, 一次 。 这将是唯一的一种方式,你可以分配aspectRatio一个值。

如果你仔细想想,你会意识到这是一个更明智和一致的方法。 以前,你对let的含义有所let ,而新的规则已经阻止你正确地做到这一点。


在你重写代码的时候,你没有初始化所有的属性,在你打算退出并返回nil 。 我知道这看起来可能是违反直觉的,但是你不能这么做。 即使您打算退出,您也必须初始化所有属性。 我在书中对此非常清楚:

failable类的初始化方法在完成所有的初始化任务之后,不能return nil 。 因此,例如,指定初始化程序的failable子类必须先看到它的所有子类的属性都已初始化,并且必须在return nil之前调用super.init(...) 。 (这里有一些好吃的讽刺:在将事件推倒之前,初始化程序必须完成构build实例。)

编辑:请注意,从Swift 2.2开始,这个要求将被解除。 初始化属性之前 return nil是合法的。 这将把类初始化器与struct初始化器放在一起,这已经是合法的了。