我今天看到了这段代码,并想知道为什么你不会使用简单的静态存储属性?
这是我很好奇的代码:
class ApiKeys {
// movie keys
class var HomePage: String { get { return "homepage" } }
class var Id: String { get { return "id" } }
class var Overview: String { get { return "overview" } }
class var PosterPath: String { get { return "poster_path" } }
class var ReleaseDate: String { get { return "release_date" } }
class var Runtime: String { get { return "runtime" } }
class var Tagline: String { get { return "tagline" } }
class var Title: String { get { return "title" } }
class var Rating: String { get { return "vote_average" } }
// query params
class var ApiKey: String { get { return "api_key" } }
class var Query: String { get { return "query" } }
}
这就是我编写相同代码的方式:
class ApiKeys {
static let homePage = "homepage"
static let id = "id"
static let overview = "overview"
static let posterPath = "poster_path"
static let releaseDate = "release_date"
static let runtime = "runtime"
static let tagline = "tagline"
static let title = "title"
static let rating = "vote_average"
//Query Params
static let ApiKey = "api_key"
static let query = "query"
}
没有必要覆盖变量,因此使用静态应该没问题。我错过了什么吗?在第二种方法中使用第一种方法是否有任何优势或理由?
答案 0 :(得分:2)
对于它的价值,我根本不会倾向于使用计算或存储的属性。而不是将其定义为class
,这似乎是enum
的教科书案例:
enum ApiKey: String {
// movie keys
case HomePage = "homepage"
case Id = "id"
case Overview = "overview"
case PosterPath = "poster_path"
case ReleaseDate = "release_date"
case Runtime = "runtime"
case Tagline = "tagline"
case Title = "title"
case Rating = "vote_average"
// query params
case ApiKey = "api_key"
case Query = "query"
}
这更准确地捕捉了“键”可以是其中一个值的概念。
你会这样使用它:
if key == ApiKey.HomePage.rawValue {
...
}
或者
if ApiKey(rawValue: key) == .HomePage {
...
}
在回答您的原始问题时,“我应该何时更喜欢计算属性”,答案是您通常使用它们来检索从其他属性计算的值,并且可选地,如果您想要设置其他(可能是私有的)属性和间接的价值观。如果您只是要返回一些静态的,不变的字符串,那么使用计算属性几乎没有什么好处。
答案 1 :(得分:1)
类var可以被子类覆盖,而静态常量则不能。这是我能想到的第一个区别。
答案 2 :(得分:1)
如果需要,可以使用计算属性在运行时动态更改属性的值,就像在Objective-C中覆盖getter一样。您不能使用static let
常量。
答案 3 :(得分:1)
可能有些偏离主题:但是如果使用默认实现定义非蓝图静态计算属性,那么静态存储属性无法使用的一种可能的设计使用方案是一些“常量”协议的扩展。符合这种协议的类/结构/等可以被允许访问类型约束泛型,其中这些泛型是唯一可以访问协议常量的上下文(限制对常量的可访问性),它们保证是常量(因为它们也可以直接从符合该协议的具体类型中使用,但是这些可以用新值“覆盖”“常量”。)
protocol HasAccessToConstants {
/* since we don't blueprint 'theAnswer', the default
implementation below will always be used for objects
conforming to this protocol when used in a generic
context (even if they attempt to "override" these
"constants" with implementations of their own, these
custom ones can only be accessed for concrete-types). */
}
extension HasAccessToConstants {
static var theAnswer: Int { return 42 }
/* for protocols: we may implement a default
implementation only for computed properties */
}
class Foo : HasAccessToConstants {
/* Even if the developer implements its own "constant"
implementation, this will not be used for accessing
Foo type in a generic context. */
static var theAnswer: Int { return 9 }
}
func onlyForObjectsWithAccessToConstants<T: HasAccessToConstants>(obj: T) {
// do something with obj ...
// make use of constants available to the type of obj
print("Constants available to the type of this object (e.g. '\(T.theAnswer)')")
}
onlyForObjectsWithAccessToConstants(Foo())
/* Constants available to the type of this object (e.g. '42') */
// not really "constants" as they can be "overridden" for concrete types
print(Foo.theAnswer) // 9 (since concrete type)
再次,设计,并包括在技术讨论中,因为我不能真正看到在哪种情况下这将比其他更好的替代品更有用。