Swift 无引用计数 (NRC)

Swift 中不使用 ARC/引用计数的对象。

这是一个实验性的想法,旨在提供 Swift 中不包含引用计数和其他内置于原生 Swift 类中的特性的对象,从而减少性能开销。

核心概念是使用 Swift 宏来美化 UnsafeMutablePointerUnsafeMutableRawPointer 的用法,以创建一个简单的对象系统。

设置

    
    dependencies: [
        .package(
            url: "https://github.com/joehinkle11/SwiftNRC",
            .upToNextMajor(from: "1.0.0")),
    ],
    targets: [
        .target(
            name: "YourTarget",
            plugins: ["SwiftNRC"]
        ),
    ]

示例

@NRC(
    members: [
        "var y": Int.self,
        "private var x": Double.self,
        "internal var z": Bool.self,
    ]
)
struct Example: SwiftNRCObject {
    
    init() {
        self = Self.allocate((
            y: 5,
            x: 4.3,
            z: true
        ))
    }
    
    func flipZ() {
        self.z.toggle()
    }
    
    func delete() {
        self.deallocate()
    }
}

let example = Example()
// XCTAssertEqual(example.x, 4.3) // no access, x is private
XCTAssertEqual(example.y, 5)
XCTAssertEqual(example.z, true)
example.z = false
XCTAssertEqual(example.z, false)
func scoped(_ copiedRef: Example) {
    copiedRef.y = 100
}
XCTAssertEqual(example.y, 5)
scoped(example)
XCTAssertEqual(example.y, 100)

静态数组支持

现在您还可以像在 C 结构体中一样,在对象的其他属性之间分配一个静态数组

@NRC(
    members: [
        "let before" : String.self,
        "var myArray": NRCStaticArray(Int.self, 10),
        "let after" : String.self,
    ]
)
struct ExampleStaticArray: SwiftNRCObject {
    
    init?(_ numbers: Int...) {
        guard numbers.count == Self.myArrayCount else {
            return nil
        }
        self = .allocate()
        self.initialize_before(to: "before string")
        for (i, number) in numbers.enumerated() {
            self.myArray.initialize(index: i, to: number)
        }
        self.initialize_after(to: "after string")
    }
    func delete() {
        self.deallocate()
    }
    
}

func arrayUsage() {
    let exampleStaticArray = ExampleStaticArray(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)!
    for i in 0..<10 {
        XCTAssertEqual(exampleStaticArray.myArray[i], 9 - i)
        exampleStaticArray.myArray[i] = i
    }
    let pointerToFirstElement = exampleStaticArray.myArrayPointer
}

所有静态数组的值(以及属性)在内存中都是连续的。这意味着您可以将指向数组第一个元素的指针传递给 C 函数,并且它可以读取数组中的所有值。

用例

使用这些非引用计数的对象比 Swift 中的传统类性能更高。在性能至关重要的应用程序中,这种对象可以帮助减少与 ARC 相关的开销。