"Extensions may not contain stored properties"除非你是Apple?我错过了什么?
"Extensions may not contain stored properties" unless your are Apple? What am I missing?
为什么苹果可以做到这一点:
import CoreGraphics
import GameplayKit
import simd
/**
@header
SceneKit framework category additions related to GameplayKit integration.
@copyright 2017 Apple, Inc. All rights reserve.
*/
extension SCNNode {
/**
* The GKEntity associated with the node via a GKSCNNodeComponent.
*
* @see GKEntity
*/
@available(OSX 10.13, *)
weak open var entity: GKEntity?
}
/**
* Adds conformance to GKSceneRootNodeType for usage as rootNode of GKScene
*/
extension SCNScene : GKSceneRootNodeType {
}
...我不能这样做:
extension SCNNode {
weak open var ntity: GKEntity?
}
并得到两个错误:
- 'weak' 只能应用于 class 和 class 绑定的协议类型,而不是 '<
>'
- 扩展不能包含存储的属性
我实际上想做的是在 10.13 之前的 OSX 版本上提供一个实体 属性,因此也欢迎对此提出其他建议。
Swift 目前无法做到这一点。正如 Sulthan 所指出的,这是一个 Objective-C 类别,您会看到 Swift 版本,它由 Xcode.
生成
现在,Objective-C不支持在类别中添加属性(扩展在Objective-C中称为类别),但您可以使用关联对象来获取您想要的内容。
Matt Thompson 在他的 NSHipster 博客上发表了一篇关于关联对象的精彩文章:Associated Objects - NSHipster
有趣的是,我和OP的感觉是一样的。 Apple 自己查看此博客 post:https://developer.apple.com/swift/blog/?id=37
您会注意到他们明显违反了他们唯一的规则,并且他们解释了如何使用 JSON 和不可编译的代码。
extension Restaurant {
private let urlComponents: URLComponents // base URL components of the web service
private let session: URLSession // shared session for interacting with the web service
static func restaurants(matching query: String, completion: ([Restaurant]) -> Void) {
var searchURLComponents = urlComponents
searchURLComponents.path = "/search"
searchURLComponents.queryItems = [URLQueryItem(name: "q", value: query)]
let searchURL = searchURLComponents.url!
session.dataTask(url: searchURL, completion: { (_, _, data, _)
var restaurants: [Restaurant] = []
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
for case let result in json["results"] {
if let restaurant = Restaurant(json: result) {
restaurants.append(restaurant)
}
}
}
completion(restaurants)
}).resume()
}
}
整篇文章都是关于如何在 Swift 中处理 JSON,因此 "Restaurants" 未在任何 Objective-C 代码中定义。
你可以试试这个代码,我用的是 Xcode 8.3.3 和 Swift 3.1:
import SceneKit
import GameplayKit
extension SCNNode {
@available(OSX 10.13, *)
public var entity: GKEntity? {
return self.entity
}
}
Swift 4 / iOS 11 / Xcode 9.2
这里的答案在技术上是正确的,但无论如何这里有一个解决方案。
在您的扩展中,定义一个包含您需要的字段的私有结构。使一切静态化,像这样:
private struct theAnswer {
static var name: String = ""
}
我知道,我知道,静态意味着它是一个 class-wide variable/property,而不是一个实例。但是我们实际上并不打算在这个结构中存储任何东西。
在下面的代码中,obj_getAssociatedObject 和 objc_setAssociatedObject 都需要一个 UnsafeRawPointer 作为键。我们使用这些函数来存储与此唯一实例关联的 key/value 对。
这是带有字符串的完整示例:
import Foundation
class ExtensionPropertyExample {
// whatever
}
extension ExtensionPropertyExample {
private struct theAnswer {
static var name: String = ""
}
var name: String {
get {
guard let theName = objc_getAssociatedObject(self, &theAnswer.name) as? String else {
return ""
}
return theName
}
set {
objc_setAssociatedObject(self, &theAnswer.name, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}
in Swift 5, Xcode 13 我能够使用静态将 属性 直接添加到扩展中(无需创建内部结构等)
例如:
extension String {
static var onboarded = "onboarded"
static var locationAllowed = "locationAllowed"
}
用法:
@AppStorage(.locationAllowed) var locationAllowed = false
@AppStorage(.onboarded) var a = false
@AppStorage
需要一个“字符串”作为参数,所以我只使用了扩展
中的 .onboarded
为什么苹果可以做到这一点:
import CoreGraphics
import GameplayKit
import simd
/**
@header
SceneKit framework category additions related to GameplayKit integration.
@copyright 2017 Apple, Inc. All rights reserve.
*/
extension SCNNode {
/**
* The GKEntity associated with the node via a GKSCNNodeComponent.
*
* @see GKEntity
*/
@available(OSX 10.13, *)
weak open var entity: GKEntity?
}
/**
* Adds conformance to GKSceneRootNodeType for usage as rootNode of GKScene
*/
extension SCNScene : GKSceneRootNodeType {
}
...我不能这样做:
extension SCNNode {
weak open var ntity: GKEntity?
}
并得到两个错误:
- 'weak' 只能应用于 class 和 class 绑定的协议类型,而不是 '<
>' - 扩展不能包含存储的属性
我实际上想做的是在 10.13 之前的 OSX 版本上提供一个实体 属性,因此也欢迎对此提出其他建议。
Swift 目前无法做到这一点。正如 Sulthan 所指出的,这是一个 Objective-C 类别,您会看到 Swift 版本,它由 Xcode.
生成现在,Objective-C不支持在类别中添加属性(扩展在Objective-C中称为类别),但您可以使用关联对象来获取您想要的内容。
Matt Thompson 在他的 NSHipster 博客上发表了一篇关于关联对象的精彩文章:Associated Objects - NSHipster
有趣的是,我和OP的感觉是一样的。 Apple 自己查看此博客 post:https://developer.apple.com/swift/blog/?id=37
您会注意到他们明显违反了他们唯一的规则,并且他们解释了如何使用 JSON 和不可编译的代码。
extension Restaurant {
private let urlComponents: URLComponents // base URL components of the web service
private let session: URLSession // shared session for interacting with the web service
static func restaurants(matching query: String, completion: ([Restaurant]) -> Void) {
var searchURLComponents = urlComponents
searchURLComponents.path = "/search"
searchURLComponents.queryItems = [URLQueryItem(name: "q", value: query)]
let searchURL = searchURLComponents.url!
session.dataTask(url: searchURL, completion: { (_, _, data, _)
var restaurants: [Restaurant] = []
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
for case let result in json["results"] {
if let restaurant = Restaurant(json: result) {
restaurants.append(restaurant)
}
}
}
completion(restaurants)
}).resume()
}
}
整篇文章都是关于如何在 Swift 中处理 JSON,因此 "Restaurants" 未在任何 Objective-C 代码中定义。
你可以试试这个代码,我用的是 Xcode 8.3.3 和 Swift 3.1:
import SceneKit
import GameplayKit
extension SCNNode {
@available(OSX 10.13, *)
public var entity: GKEntity? {
return self.entity
}
}
Swift 4 / iOS 11 / Xcode 9.2
这里的答案在技术上是正确的,但无论如何这里有一个解决方案。
在您的扩展中,定义一个包含您需要的字段的私有结构。使一切静态化,像这样:
private struct theAnswer {
static var name: String = ""
}
我知道,我知道,静态意味着它是一个 class-wide variable/property,而不是一个实例。但是我们实际上并不打算在这个结构中存储任何东西。
在下面的代码中,obj_getAssociatedObject 和 objc_setAssociatedObject 都需要一个 UnsafeRawPointer 作为键。我们使用这些函数来存储与此唯一实例关联的 key/value 对。
这是带有字符串的完整示例:
import Foundation
class ExtensionPropertyExample {
// whatever
}
extension ExtensionPropertyExample {
private struct theAnswer {
static var name: String = ""
}
var name: String {
get {
guard let theName = objc_getAssociatedObject(self, &theAnswer.name) as? String else {
return ""
}
return theName
}
set {
objc_setAssociatedObject(self, &theAnswer.name, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}
in Swift 5, Xcode 13 我能够使用静态将 属性 直接添加到扩展中(无需创建内部结构等)
例如:
extension String {
static var onboarded = "onboarded"
static var locationAllowed = "locationAllowed"
}
用法:
@AppStorage(.locationAllowed) var locationAllowed = false
@AppStorage(.onboarded) var a = false
@AppStorage
需要一个“字符串”作为参数,所以我只使用了扩展
.onboarded