首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何获得伪装为`__SwiftValue`的快速结构的实际类型

如何获得伪装为`__SwiftValue`的快速结构的实际类型
EN

Stack Overflow用户
提问于 2020-08-20 14:46:18
回答 1查看 340关注 0票数 2

我使用YapDatabase来编码/解码我的Swift值类型。解码后,类型信息似乎丢失了,即type(of:element)返回__SwiftValue而不是Reservation

但是,如果我在调试器中调用po element,似乎仍然保留了类型信息:

代码语言:javascript
复制
(lldb) po element 
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* SecureTruckParking.Reservation(reservationId: 12625, accessInformations: [SecureTruckParking.AccessInformation(accessInformationId: 12706, accessTypeId: 1, accessTypeKey: Optional("1"), accessTypeTenantKey: Optional("ROOT"), encodedValue: "XXX", displayedValue: "XXX"), SecureTruckParking.AccessInformation(accessInformationId: 12707, accessTypeId: 51, accessTypeKey: Optional("51"), accessTypeTenantKey: Optional("ROOT"), encodedValue: "918296", displayedValue: "918296")], customerId: 3156, areaId: 552, productId: 1004, state: "PENDING", startTime: 2020-09-10 08:23:00 +0000, endTime: 2020-09-11 08:23:00 +0000, earliestEntryTime: 2020-09-10 08:23:00 +0000, latestExitTime: 2020-09-11 08:23:00 +0000, totalAmount: 2750.0, currency: "€", netPrice: 2311.0, taxPrice: 439.0, invoiceItems: [SecureTruckParking.InvoiceItem(amount: 1, itemText: "Parkplatzreservierung, 10.09.2020 10:23 - 11.09.2020 10:23 \nREWE Logistikzentrum Neu-Isenburg -> REWE Logistikzentrum Neu-Isenburg", netPrice: 2311.0, taxPrice: 439.0, taxRate: 19.0)], productAttributes: [SecureTruckParking.Attribute(key: "early_bird_count", value: Optional("1"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "early_bird_count", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "DETAILS", value: nil, definitionId: nil), SecureTruckParking.Attribute(key: "INFO_DETAILS", value: nil, definitionId: nil), SecureTruckParking.Attribute(key: "early_bird", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "early_bird", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "manualBackofficeCancellationConfirmation", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "manualBackofficeCancellationConfirmation", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "manualBackofficeCancellationConfirmationThreshold", value: Optional("1"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "manualBackofficeCancellationConfirmationThreshold", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "product_icon", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "product_icon", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "product_image", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "product_image", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "product_tariff_group", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "product_tariff_group", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_dates_fixed", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_dates_fixed", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_immediate", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_immediate", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_mail", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_mail", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_price_surcharge", value: Optional("false"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_price_surcharge", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "early_bird_duration", value: Optional("1440"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "early_bird_duration", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "recurring_max_trips", value: Optional("1"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "recurring_max_trips", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_mail_max_lead_time", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_mail_max_lead_time", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "upgrading_mail_min_lead_time", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "upgrading_mail_min_lead_time", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "bstp_product_type", value: Optional("Reservation"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "bstp_product_type", tenant: "ROOT")))], areaAttributes: [SecureTruckParking.Attribute(key: "product_icon", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "product_icon", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "product_image", value: nil, definitionId: Optional(SecureTruckParking.DefinitionId(key: "product_image", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "Parking_Area_UST", value: Optional("22222222222222"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "Parking_Area_UST", tenant: "MAN_BOSCH"))), SecureTruckParking.Attribute(key: "ipaw_id", value: Optional("4651"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "ipaw_id", tenant: "ROOT"))), SecureTruckParking.Attribute(key: "bstp_area_type", value: Optional("PROFESSIONAL"), definitionId: Optional(SecureTruckParking.DefinitionId(key: "bstp_area_type", tenant: "ROOT")))])
*/

这个__SwiftValue是什么,是否有一种获得实际类型的方法(除了解析String(describing: element的任何可怕方法之外)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-22 19:40:31

首先,您看到的是__SwiftValue,因为struct已被as AnyObject强制转换所包装。您可以轻松地亲自验证这一点:

代码语言:javascript
复制
struct TestStruct {}
let ourStruct = TestStruct()
let structSwiftValue = ourStruct as AnyObject
print(type(of: ourStruct))
print(type(of: structSwiftValue))

产出:

代码语言:javascript
复制
TestStruct
__SwiftValue

很好地讨论了这个主题:https://forums.swift.org/t/anyobject/35659/9

现在,关于您问题的本质,不幸的是,我认为目前还没有方便的公共API可以从Type中提取原始元数据Type

尽管如此,这个话题还是太有趣了,不能为了教育目的而冒险进入私人API领域。

让我们从__SwiftValue本身开始,https://github.com/apple/swift/blob/master/stdlib/public/runtime/SwiftValue.mm

通过obj-c提供了有希望的API:

代码语言:javascript
复制
// Private methods for debugging purposes.

- (const Metadata *)_swiftTypeMetadata {
  return getSwiftValueTypeMetadata(self);
}
- (id /* NSString */)_swiftTypeName {
  TypeNamePair typeName
    = swift_getTypeName(getSwiftValueTypeMetadata(self), true);
  id str = swift_stdlib_NSStringFromUTF8(typeName.data, typeName.length);
  return [str autorelease];
}
- (const OpaqueValue *)_swiftValue {
  return getValueFromSwiftValue(self).second;
}

让我们从一些相当简单的事情开始:

代码语言:javascript
复制
print(structSwiftValue.value(forKey: "_swiftTypeName")!)

产出:

代码语言:javascript
复制
ModuleName.TestStruct

只是一种String类型,但对初学者来说并不坏。下一个有希望的候选人似乎是:

代码语言:javascript
复制
- (const Metadata *)_swiftTypeMetadata()

我们可以这样称呼它(关于在Swift中调用选择器的这种特殊方式的详细信息可以找到here)

代码语言:javascript
复制
let selector: Selector = NSSelectorFromString("_swiftTypeMetadata")
let methodIMP: IMP! = structSwiftValue.method(for: selector)
let metadataPtr = unsafeBitCast(methodIMP,to:(@convention(c)(Any?,Selector)->OpaquePointer).self)(structSwiftValue,selector)

现在的挑战是以一种Metadata *的方式使用OpaquePointer (即桥接到Swift之后的OpaquePointer)。

我找到了一种方法,尽管是一种非常讨厌的方法。

我们从某个虚拟对象或结构的元数据Type变量开始(并不重要)。总的想法是,我们最终希望用我们从上一阶段获得的元数据指针来代替元数据指针。我注意到type(of:)的结果产生了指向元数据的指针,因此还有额外的间接级别,我们必须适应这样的情况:

代码语言:javascript
复制
var placeholderTypeVar: Any.Type = type(of: NSObject())
print(placeholderTypeVar)
withUnsafeMutablePointer(to: &placeholderTypeVar) {
    let unsafePtr = UnsafeMutablePointer<OpaquePointer>.allocate(capacity: 1)
    unsafePtr.pointee = metadataPtr
    $0.assign(from: UnsafePointer<Any.Type>.init(OpaquePointer(unsafePtr)), count: 1)
}
print(placeholderTypeVar)
print(type(of: structSwiftValue))

产出:

代码语言:javascript
复制
NSObject
TestStruct
__SwiftValue

中间的是答案。而且,它与type(of: ourStruct)的结果相同,直到内存级别(内部产生的Metadata *等效值是完全相同的地址!)。

更多地阅读元数据,这是Swift中一个非常有趣的主题:

https://medium.com/ios-os-x-development/types-and-meta-types-in-swift-9cd59ba92295 https://kateinoigakukun.hatenablog.com/entry/2019/03/22/184356 https://medium.com/@weswickwire/creating-a-swift-runtime-library-3cc92fc486cc

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63507627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档