簡體   English   中英

“擴展可能不包含存儲的屬性”,除非你是 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 和類綁定協議類型,而不是 '<<error type>>'
  • 擴展不能包含存儲的屬性

我實際上想做的是在 10.13 之前的 OSX 版本上提供一個實體屬性,因此也歡迎對此提出其他建議。

Swift 4 / iOS 11 / Xcode 9.2

這里的答案在技術上是正確的,但無論如何這里都是一個解決方案。

在您的擴展中,使用您想要的字段定義私有結構。 讓一切都是靜態的,像這樣:

private struct theAnswer {
    static var name: String = ""
}

我知道,我知道,靜態意味着它是一個類范圍的變量/屬性,而不是實例。 但我們實際上並沒有在這個結構中存儲任何東西。

在下面的代碼中, obj_getAssociatedObjectobjc_setAssociatedObject都需要UnsafeRawPointer作為鍵。 我們使用這些函數來存儲與此唯一實例關聯的鍵/值對。

這是帶字符串的完整示例:

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)
        }
    }
}

這在Swift中目前是不可能的。 正如Sulthan所指出的,這是一個Objective-C類別,您可以看到由Xcode生成的Swift版本。

現在,Objective-C不容易支持在類別中添加屬性(擴展在Objective-C中稱為類別),但您可以使用關聯的對象來獲得所需的內容。

Mattt Thompson在他的NSHipster博客上發表了一篇關於相關對象的精彩文章: Associated Objects - NSHipster

有趣我和OP有同樣的感覺。 查看Apple本身的博文: 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的,因此在任何Objective-C代碼中都沒有定義“Restaurants”。

您可以嘗試使用此代碼,我正在使用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 5, Xcode 13 我可以使用 static 將屬性直接添加到擴展中(無需創建內部結構等。)

例如:

extension String {
   static var onboarded = "onboarded"
   static var locationAllowed = "locationAllowed"
}

用法:

@AppStorage(.locationAllowed) var locationAllowed = false
@AppStorage(.onboarded) var a = false

@AppStorage需要一個“字符串”作為參數,所以我只是使用擴展中的.onboarded

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM