swift class struct bridge

swift class properties



Define struct que se trata como una clase en Swift (3)

En última instancia, el puente entre String y NSString es bastante simple.

NSString solo tiene 2 variables de instancia (El puntero de cadena nxcsptr y la longitud nxcslen ). String utiliza _StringCore , que solo tiene 3 propiedades ( _baseAddress , _countAndFlags y _owner ). La conversión de ida y vuelta está codificada de forma rígida y el compilador la llama explícitamente. No hay un sistema automático implementado para generar clases fuera de las estructuras, o viceversa.

Tendrás que implementar un par de struct / class (como con String y NSString ) e implementar los inicializadores que construyen uno desde el otro.

En Swift, una estructura String también se trata como un objeto de clase, como cuando se utiliza el NSCoder encodeObject(_:forKey:) . Sé que String está puenteado directamente con la clase NSString -c, NSString , pero ¿hay alguna manera de hacer una struct personalizada que se comporte de manera similar? ¿Quizás lo vincule a una clase personalizada? Quiero ser capaz de hacer algo como esto:

struct SortedArray <Value: Comparable> {} // Would I need to create a bridge between // SortedArray and NSSortedArray? Can I even do that? class NSSortedArray <Value: Comparable> : NSObject, NSCoding { required init?(coder aDecoder: NSCoder) {} func encodeWithCoder(aCoder: NSCoder) {} } class MyClass : NSObject, NSCoding { private var objects: SortedArray<String> = SortedArray<String>() required init?(coder aDecoder: NSCoder) { guard let objects = aDecoder.decodeObjectForKey("objects") as? SortedArray<String> else { return nil } self.objects = objects } func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(objects, forKey: "objects") } }


Esto no es posible actualmente. SE-0058 lo abordará, pero se difiere de Swift 3. Se esperaría que una implementación final de SE-0058 maneje algo más que solo el puente ObjC; por ejemplo, permitir el puente C ++ o .NET también en una solución más genérica.


Encontré una solución elegante y funcional que funciona con una struct _ObjectiveCBridgeable que puede codificar NSCoder ; gracias a la referencia que proporcionó Martin R. Aquí está el código de la biblioteca que escribí para cualquier persona interesada. Ahora puedo hacer algo como esto:

func init?(coder aDecoder: NSCoder) { guard let numbers = aDecoder.decodeObjectForKey("Numbers") as? SortedArray<Int> else { return nil } print(numbers) // Outputs "[1,3,5]" } func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(SortedArray<Int>([1,5,3]), forKey: "Numbers") }

SortedArray.swift

// // SortedArray.swift // NoodleKit // // Created by Thom Morgan on 8/15/16. // Copyright © 2016 CocoaPods. All rights reserved. // // MARK: - ** Import Modules ** import Foundation // MARK: - ** SortOrder Enumeration ** /// Ascending or descending sort order enumerations public enum SortOrder : Int { case Ascending, Descending } // MARK: - ** SortedArray Structure ** /// An array data structure that automatically places elements in order as /// they added to the collection. public struct SortedArray <Value: Comparable> : CollectionType, _ObjectiveCBridgeable, CustomStringConvertible { // MARK: - _ObjectiveCBridgeable /// Required typealias from the `_ObjectiveCBridgeable` private protocol public typealias _ObjectiveCType = NSSortedArray<Value> // MARK: - CollectionType public typealias Index = Int public typealias Generator = IndexingGenerator<SortedArray<Value>> public var startIndex: Index { return 0 } public var endIndex: Index { return values.count } public var range: Range<Index> { return 0 ..< values.count } public var count: Int { return values.count } // MARK: - CustomStringConvertible public var description: String { return "/(values)" } // MARK: - SortedArray /// The order in which to sort array elements. public var sortOrder: SortOrder { willSet { if sortOrder != newValue { values = values.reverse() } } } /// The elements of this array. public private (set) var values = [Value]() /// Whether or not to allow duplicate elements to be added to this array. public var uniqueElements: Bool = true // MARK: - ** Constructor Methods ** // MARK: - SortedArray /// Verbose constructor in which the sort order can be established at /// initialization. /// - parameter sortOrder: The order in which to sort array elements. /// - parameter values: The initial elements to populate this array. /// - note: The initial values parameter need not be sorted, as it will /// automatically be sorted upon initialization. /// - returns: An array structure instance with sorted values. public init(sortOrder: SortOrder = .Ascending, values: [Value] = [Value]()) { self.sortOrder = sortOrder self.values = values.sort({ (a: Value, b: Value) -> Bool in return sortOrder == .Ascending ? (a < b) : (b < a) }) } /// Convenience constructor that sets the inital array elements. /// - parameter values: The initial elements to populate this array. /// - returns: An array structure instance with sorted values in /// ascending order. public init(_ values: [Value]) { sortOrder = .Ascending self.values = values.sort({ (a: Value, b: Value) -> Bool in return a < b }) } /// Duplicating constructor. /// - parameter sortedArray: Another array to initialize from. /// - returns: An array structure instance with sorted values /// identical to `sortedArray`. public init(_ sortedArray: SortedArray<Value>) { sortOrder = sortedArray.sortOrder values = sortedArray.values } /// Bridging constructor from an `NSSortedArray` class instance. /// - parameter sortedArray: Another array to initialize from. /// - returns: An array structure instance with sorted values /// identical to `sortedArray`. public init(_ sortedArray: NSSortedArray<Value>) { sortOrder = sortedArray.sortOrder values = sortedArray.values } // MARK: - ** Public Methods ** // MARK: - _ObjectiveCBridgeable /// Required static method from the `_ObjectiveCBridgeable` private /// protocol. /// - returns: `true`, indicating that this structure is bridgeable to /// an Objective-C class, namely `NSSortedArray`. public static func _isBridgedToObjectiveC() -> Bool { return true } /// Required static method from the `_ObjectiveCBridgeable` private /// protocol. /// - returns: `NSSortedArray<Value>.self` public static func _getObjectiveCType() -> Any.Type { return _ObjectiveCType.self } /// Required static method from the `_ObjectiveCBridgeable` private /// protocol. /// - parameter source: An `NSSortedArray<Value>` instance to force bridge /// to `SortedArray<Value>`. /// - parameter result: The `SortedArray<Value>` instance created from /// the forced bridging. public static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: SortedArray<Value>?) { result = SortedArray<Value>(source) } /// Required static method from the `_ObjectiveCBridgeable` private /// protocol. /// - parameter source: An `NSSortedArray<Value>` instance to conditionally /// bridge to `SortedArray<Value>`. /// - parameter result: The `SortedArray<Value>` instance created from /// the conditional bridging. public static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: SortedArray<Value>?) -> Bool { _forceBridgeFromObjectiveC(source, result: &result) return true } /// Required method from the `_ObjectiveCBridgeable` private protocol /// - returns: An `NSStortedArray<Value>` instance identical to `self`. public func _bridgeToObjectiveC() -> _ObjectiveCType { return NSSortedArray<Value>(self) } // MARK: - CollectionType public subscript (index: Index) -> Value { get { return values[index] } set { values[index] = newValue } } public func generate() -> Generator { return Generator(SortedArray(values: values)) } /// Insert `newElement` at index `i`. /// /// - requires: `i <= count`. /// /// - complexity: O(`self.count`). public mutating func insert(value: Value, atIndex index: Index) { values.insert(value, atIndex: index) } /// Remove and return the element at index `i`. /// /// Invalidates all indices with respect to `self`. /// /// - complexity: O(`self.count`). public mutating func removeAtIndex(index: Index) -> Value { return values.removeAtIndex(index) } /// Remove all elements. /// /// - postcondition: `capacity == 0` iff `keepCapacity` is `false`. /// /// - complexity: O(`self.count`). public mutating func removeAll() { values.removeAll() } // MARK: - SortedArray /// Returns the first index where `value` appears in `self` or `nil` if /// `value` is not found. /// /// - note: This is a significantly less costly implementation of the /// default system method `indexOf(element: Element)`. /// /// - complexity: O(`log(self.count)`) /// /// - parameter value: The value to search for /// - parameter range: The range to search within. If `nil` the entire /// range of elements are searched. /// - returns: The first index where `value` appears in `self` or `nil` if /// `value` is not found. @warn_unused_result public func indexOf(value: Value, searchRange range: Range<Index>? = nil) -> Index? { if values.count == 0 { return nil } let range = range ?? 0 ..< values.count let index = (range.startIndex + range.length / 2) let val = values[index] if range.length == 1 { return val == value ? index : nil } else if (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) { return indexOf(value, searchRange: range.startIndex ..< index) } return indexOf(value, searchRange: index ..< range.endIndex) } /// Returns the first index where `value` would be placed in sorted order /// in `self`. /// /// - complexity: O(`log(self.count)`) /// /// - parameter value: The value to search for. /// - parameter range: The range to search within. If `nil` the entire /// range of elements are searched. /// - returns: Returns the first index where `value` would be placed /// in sorted order. @warn_unused_result public func ordinalIndexForValue(value: Value, searchRange range: Range<Index>? = nil) -> Index { if values.count == 0 { return 0 } let range = range ?? 0 ..< values.count let index = (range.startIndex + range.length / 2) let val = values[index] if range.length == 1 { return (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) ? index : index + 1 } else if (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) { return ordinalIndexForValue(value, searchRange: range.startIndex ..< index) } return ordinalIndexForValue(value, searchRange: index ..< range.endIndex) } /// Adds a value to `self` in sorted order. /// - parameter value: The value to add. /// - returns: The index where `value` was inserted, or `nil` if /// `uniqueElements` is set to `true` and `value` already exists in /// `self. /// /// - complexity: O(`log(self.count)`) public mutating func add(value: Value) -> Index? { var index = 0 if values.count == 0 { values.append(value) } else { if uniqueElements && indexOf(value) != nil { return nil } index = ordinalIndexForValue(value) values.insert(value, atIndex: index) } return index } /// Removes all instances of `value` from `self` /// - parameter value: The `value` to remove from `self`. /// /// - complexity: O(`log(self.count) * n`) where `n` is the number of /// times `value` occurs in `self`. public mutating func remove(value: Value){ var index = indexOf(value) while index != nil { values.removeAtIndex(index!) index = indexOf(value) } } }

NSSortedArray.swift

// // NSSortedArray.swift // NoodleKit // // Created by Thom Morgan on 6/29/16. // Copyright © 2016 NoodleOfDeath. All rights reserved. // // MARK: - ** Import Modules ** import Foundation private struct CodingKeys { static let SortOrder = "SortOrder" static let Values = "Values" } // MARK: - ** NSSortedArray Class ** /// An array class that automatically places elements in order as /// they added to the collection. public class NSSortedArray <Value: Comparable> : NSObject, CollectionType, NSCoding { // MARK: - CollectionType public typealias Index = Int public typealias Generator = IndexingGenerator<NSSortedArray<Value>> public var startIndex: Index { return 0 } public var endIndex: Index { return values.count } public var range: Range<Index> { return 0 ..< values.count } public var count: Int { return values.count } // MARK: - CustomStringConvertible public override var description: String { return "/(values)" } // MARK: - NSSortedArray /// The order in which to sort array elements. public var sortOrder: SortOrder { willSet { if sortOrder != newValue { values = values.reverse() } } } /// The elements of this array. public private (set) var values = [Value]() /// Whether or not to allow duplicate elements to be added to this array. public var uniqueElements: Bool = true // MARK: - ** Constructor Methods ** // MARK: - NSSortedArray /// Verbose constructor in which the sort order can be established at /// initialization. /// - parameter sortOrder: The order in which to sort array elements. /// - parameter values: The initial elements to populate this array. /// - note: The initial values parameter need not be sorted, as it will /// automatically be sorted upon initialization. /// - returns: An array structure instance with sorted values. public init(sortOrder: SortOrder = .Ascending, values: [Value] = [Value]()) { self.sortOrder = sortOrder self.values = values.sort({ (a: Value, b: Value) -> Bool in return sortOrder == .Ascending ? (a < b) : (b < a) }) } /// Convenience constructor that sets the inital array elements. /// - parameter values: The initial elements to populate this array. /// - returns: An array structure instance with sorted values in /// ascending order. public init(_ values: [Value]) { sortOrder = .Ascending self.values = values.sort({ (a: Value, b: Value) -> Bool in return a < b }) } /// Duplicating constructor. /// - parameter sortedArray: Another array to initialize from. /// - returns: An array structure instance with sorted values /// identical to `sortedArray`. public init(_ sortedArray: NSSortedArray<Value>) { sortOrder = sortedArray.sortOrder values = sortedArray.values } /// Bridging constructor from a `SortedArray` structure instance. /// - parameter sortedArray: Another array to initialize from. /// - returns: An array class instance with sorted values /// identical to `sortedArray`. public init(_ sortedArray: SortedArray<Value>) { sortOrder = sortedArray.sortOrder values = sortedArray.values } // MARK: - NSCoding public convenience required init?(coder aDecoder: NSCoder) { guard let sortOrder = SortOrder(rawValue: aDecoder.decodeIntegerForKey(CodingKeys.SortOrder)) else { return nil } guard let values = aDecoder.decodeObjectForKey(CodingKeys.Values) as? [Value] else { return nil } self.init(sortOrder: sortOrder, values: values) } public func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeInteger(sortOrder.rawValue, forKey: CodingKeys.SortOrder) aCoder.encodeObject(values, forKey: CodingKeys.Values) } // MARK: - CollectionType public subscript (index: Index) -> Value { get { return values[index] } set { values[index] = newValue } } public func generate() -> Generator { return Generator(NSSortedArray(values: values)) } /// Insert `newElement` at index `i`. /// /// - requires: `i <= count`. /// /// - complexity: O(`self.count`). public func insert(value: Value, atIndex index: Index) { values.insert(value, atIndex: index) } /// Remove and return the element at index `i`. /// /// Invalidates all indices with respect to `self`. /// /// - complexity: O(`self.count`). public func removeAtIndex(index: Index) -> Value { return values.removeAtIndex(index) } /// Remove all elements. /// /// - postcondition: `capacity == 0` iff `keepCapacity` is `false`. /// /// - complexity: O(`self.count`). public func removeAll(keepCapacity keepCapacity: Bool = false) { values.removeAll(keepCapacity: keepCapacity) } // MARK: - NSSortedArray /// Returns the first index where `value` appears in `self` or `nil` if /// `value` is not found. /// /// - note: This is a significantly less costly implementation of the /// default system method `indexOf(element: Element)`. /// /// - complexity: O(`log(self.count)`) /// /// - parameter value: The value to search for. /// - parameter range: The range to search within. If `nil` the entire /// range of elements are searched. /// - returns: The first index where `value` appears in `self` or `nil` if /// `value` is not found. @warn_unused_result public func indexOf(value: Value, searchRange range: Range<Index>? = nil) -> Index? { if values.count == 0 { return nil } let range = range ?? 0 ..< values.count let index = (range.startIndex + range.length / 2) let val = values[index] if range.length == 1 { return val == value ? index : nil } else if (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) { return indexOf(value, searchRange: range.startIndex ..< index) } return indexOf(value, searchRange: index ..< range.endIndex) } /// Returns the first index where `value` would be placed in sorted order /// in `self`. /// /// - complexity: O(`log(self.count)`) /// /// - parameter value: The value to search for. /// - parameter range: The range to search within. If `nil` the entire /// range of elements are searched. /// - returns: The first index where `value` would be placed in sorted /// order in `self`. @warn_unused_result public func ordinalIndexForValue(value: Value, searchRange range: Range<Index>? = nil) -> Index { if values.count == 0 { return 0 } let range = range ?? 0 ..< values.count let index = (range.startIndex + range.length / 2) let val = values[index] if range.length == 1 { return (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) ? index : index + 1 } else if (val > value && sortOrder == .Ascending) || (val < value && sortOrder == .Descending) { return ordinalIndexForValue(value, searchRange: range.startIndex ..< index) } return ordinalIndexForValue(value, searchRange: index ..< range.endIndex) } /// Adds a value to `self` in sorted order. /// - parameter value: The value to add. /// - returns: The index where `value` was inserted, or `nil` if /// `uniqueElements` is set to `true` and `value` already exists in /// `self. /// /// - complexity: O(`log(self.count)`) public func add(value: Value) -> Index? { var index = 0 if values.count == 0 { values.append(value) } else { if uniqueElements && indexOf(value) != nil { return nil } index = ordinalIndexForValue(value) values.insert(value, atIndex: index) } return index } /// Removes all instances of `value` from `self` /// - parameter value: The `value` to remove from `self`. /// /// - complexity: O(`log(self.count) * n`) where `n` is the number of /// times `value` occurs in `self`. public func remove(value: Value){ var index = indexOf(value) while index != nil { values.removeAtIndex(index!) index = indexOf(value) } } }

NSCoder.swift

// // NSCoder.swift // NoodleKit // // Created by Thom Morgan on 8/15/16. // Copyright © 2016 CocoaPods. All rights reserved. // // MARK: - ** Import Modules ** import Foundation // MARK: - ** NSCoder - _ObjectiveCBridgeable Encoding Compatibility ** extension NSCoder { /// Encodes an `_ObjectiveCBridgeable` data structure. /// - important: The objective-c class being bridged to must conform to /// `NSCoding`. /// - parameter object: The object to encode. public func encodeObject<T: _ObjectiveCBridgeable>(object: T?) { encodeObject(object?._bridgeToObjectiveC()) } /// Encodes an `_ObjectiveCBridgeable` data structure as a root object. /// - important: The objective-c class being bridged to must conform to /// `NSCoding`. /// - parameter object: The object to encode. public func encodeRootObject<T: _ObjectiveCBridgeable>(object: T) { encodeRootObject(object._bridgeToObjectiveC()) } /// Encodes an `_ObjectiveCBridgeable` conditional data structure. /// - important: The objective-c class being bridged to must conform to /// `NSCoding`. /// - parameter object: The object to encode. public func encodeConditionalObject<T: _ObjectiveCBridgeable>(object: T?) { encodeConditionalObject(object?._bridgeToObjectiveC()) } /// Encodes an `_ObjectiveCBridgeable` data structure and maps it to a /// specific `key`. /// - important: The objective-c class being bridged to must conform to /// `NSCoding`. /// - parameter object: The object to encode. /// - parameter key: The key to associate with this object. public func encodeObject<T: _ObjectiveCBridgeable>(object: T?, forKey key: String) { encodeObject(object?._bridgeToObjectiveC(), forKey: key) } /// Encodes an `_ObjectiveCBridgeable` conditional data structure and maps /// it to a specific `key`. /// - important: The objective-c class being bridged to must conform to /// `NSCoding`. /// - parameter object: The object to encode. /// - parameter key: The key to associate with this object. public func encodeConditionalObject<T: _ObjectiveCBridgeable>(object: T?, forKey key: String) { encodeConditionalObject(object?._bridgeToObjectiveC(), forKey: key) } }