我是 Swift 的新手,所以我可能會遺漏一些基礎知識。
我有結構:
struct MyStruct {
var a: Int
var b: String
var c: Bool
init() {
a: Int = 1,
b: String? = "",
c: Bool? = false
}
}
和函式,它應該遍歷給定的結構屬性并在 json 中回傳它們的型別:
func structProps(){
let elm = MyStruct()
let mirror = Mirror(reflecting: elm)
var exampleDict: [String: String] = [:]
for child in mirror.children {
exampleDict[child.label!] = String(describing:type(of: child.value)) as String
}
if let theJSONData = try? JSONSerialization.data(
withJSONObject: exampleDict,
options: []) {
let theJSONText = String(data: theJSONData, encoding: .ascii)
}
}
它有點回傳我需要的東西:
JSON string = {"a":"Int","b":"String","c":"Bool"}
因為我有很多結構,并且我想從所有結構中匯出 json,所以我想知道是否有辦法擁有通用初始化程式。不傳遞默認值。
意思是沒有
init() {
a: Int = 1,
b: String? = "",
c: Bool? = false
}
uj5u.com熱心網友回復:
如果我理解正確,您可以創建一個基本協議并將其作為擴展添加到您的結構中,例如
protocol BaseFunction {
func getElements() -> [String : String]
func getDict() -> String
}
extension BaseFunction {
func getElements() -> [String : String] {
let mirror = Mirror(reflecting: self)
let propertiesRemoveNil = mirror.children.filter({!(($0.value as AnyObject) is NSNull)})
let properties = propertiesRemoveNil.compactMap({$0.label})
var types = [String]()
_ = mirror.children.forEach({
types.append(String(describing:type(of: $0.value)))
})
return Dictionary(uniqueKeysWithValues: zip(properties, types))
}
func getDict() -> String{
if let theJSONData = try? JSONSerialization.data(
withJSONObject: getElements(),
options: []) {
let theJSONText = String(data: theJSONData, encoding: .ascii)
return theJSONText ?? ""
}
return ""
}
}
和用法:
func structProps(){
let elm = MyStruct()
print(elm.getDict())
}
輸出 :
{"a":"Int","b":"String","c":"Bool"}
uj5u.com熱心網友回復:
Mirror(reflecting:)需要一個型別的實體,而不是型別本身,ref。一個想法是擁有一個通用函式,該函式適用于所有符合提供空 init 的協議的型別。就像是:
protocol EmptyInitializable {
init()
}
struct StructOne {
let a: Bool
let b: String
}
struct StructTwo {
let c: Int
let d: Float
}
extension StructOne: EmptyInitializable {
init() {
a = false
b = ""
}
}
extension StructTwo: EmptyInitializable {
init() {
c = 1
d = 1.0
}
}
func print(subject: EmptyInitializable) -> String? {
let dictionary = Dictionary(uniqueKeysWithValues:
Mirror(reflecting: subject).children.map {
($0.label!, String(describing: type(of: $0.value)))
}
)
return (try? JSONSerialization.data(withJSONObject: dictionary)).flatMap {
String(data: $0, encoding: .utf8)
}
}
print(subject: StructOne()) // "{"a":"Bool","b":"String"}"
print(subject: StructTwo()) // "{"d":"Float","c":"Int"}"
您仍然必須實作空初始化并分配一些值,恐怕目前沒有辦法避免這種情況。
uj5u.com熱心網友回復:
我打算寫一篇關于使用協議的評論,但我認為用一些代碼作為答案會更容易理解。
為了使用法更通用,因此您不需要為每種型別的結構提供特定代碼,您應該使用協議。我更喜歡回傳新物件的靜態方法,而不是init可能與結構中已經存在的 init 沖突的方法,也稱為工廠方法
protocol PropertyExtract {
static func createEmpty() -> PropertyExtract
}
然后我們可以使用結構的默認初始化或任何提供的初始化,通過讓結構符合擴展中的協議來創建具有一些初始值的物件
extension MyStruct: PropertyExtract {
static func createEmpty() -> PropertyExtract {
MyStruct(a: 0, b: "", c: false)
}
}
而不是硬編碼或將特定型別的物件傳遞給編碼函式,我們傳遞它的型別
func structProps(for structType: PropertyExtract.Type)
并使用協議方法獲取型別的實體
let object = structType.createEmpty()
整個功能(有一些額外的變化)
func structProps(for structType: PropertyExtract.Type) -> String? {
let object = structType.createEmpty()
let mirror = Mirror(reflecting: object)
let exampleDict = mirror.children.reduce(into: [String:String]()) {
guard let label = $1.label else { return }
$0[label] = String(describing:type(of: $1.value))
}
if let data = try? JSONEncoder().encode(exampleDict) {
return String(data: data, encoding: .utf8)
}
return nil
}
And this is then called with the type of the struct
let jsonString = structProps(for: MyStruct.self)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/452928.html
標籤:迅速
上一篇:角度到Double或CGFloat或String-SwiftUI
下一篇:ForEach中的專案相互迭代
