ios - IOS Swift:在init方法(构造函数)之前运行一次代码块
问题描述
在 IOS SWIFT 中,如何实现类似于C# 中提供的静态构造函数的类似功能。
那是:
- 在 init 方法之前执行一段代码(在类中执行的第一个代码块)
- 自动调用
- 在类的生命周期中只执行一次
这是为了设置一个全局转换映射,以使用提供的名称而不是真实的类名(类名是“Order”)对类的实例进行编码。
NSKeyedUnarchiver.setClass(Order.self, forClassName: "OldModuleName.Order")
从头写一个旧APP(用SWIFT 1.2编写),项目名称不同,因此模块名称与旧版本不同。
我需要在初始化类之前运行上面提到的那段代码,并且运行一次。
class Order: NSObject, NSCoding
{
var orderID: Int = 0
var description: String = ""
// NEED TO RUN THIS LINE BEFORE INIT METHOD >>>>
// NSKeyedUnarchiver.setClass(Order.self, forClassName: "OldModuleName.Order")
override init()
{
super.init()
}
required init?(coder aDecoder: NSCoder)
{
self.orderID = (aDecoder.decodeInteger(forKey: "OrderID"))
self.description= (aDecoder.decodeObject(forKey: "Description") as? String) ?? ""
}
func encode(with aCoder: NSCoder)
{
aCoder.encode(self.orderID, forKey: "OrderID")
aCoder.encode(self.description, forKey: "Description")
}
}
编辑
我尝试编写一个如下所示的静态常量并在“ required init?(coder aDecoder: NSCoder) ”方法中调用它(因为此类符合 NSCoding 协议而不是在这种情况下调用默认的 init 方法)
static let ConfigureEncodeTranslationMapping: Void =
{
NSKeyedUnarchiver.setClass(Order.self, forClassName: "OldModuleName.Order")
return()
}()
required init?(coder aDecoder: NSCoder)
{
// call static constant here to test
Order.ConfigureEncodeTranslationMapping
self.orderID = (aDecoder.decodeInteger(forKey: "OrderID"))
self.description= (aDecoder.decodeObject(forKey: "Description") as? String) ?? ""
}
但是APP崩溃说
*由于未捕获的异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'*** - [NSKeyedUnarchiver decodeObjectForKey:]:无法解码类(OldModuleName.Order)的对象以获取键(NS.objects),因为没有名为“OldModuleName.Order”的类被找到; 该类需要在源代码中定义或从库中链接(确保该类是正确目标的一部分)。如果类被重命名,使用 setClassName:forClass: 将类转换映射添加到 NSKeyedUnarchiver*
解决方案
有一个名为的类方法load()
,每个类加载和每个应用程序启动都会自动调用一次。但它定义了Swift不允许的 Objective-C 类方法“加载” 。您可以使用 Objective-C 类并将其桥接到 Swift。
试试这个看看问题:
override class func load() {
print("Loaded")
}
这是一种动态行为,而Swift是静态的!所以你不能在不帮助 Objective-C 的情况下迅速做到这一点
相似但不一样
您可以拥有一个静态常量并调用一次(或多次,没关系):
class Order {
static let loadOnce: Void = { print("Loaded") }()
}
Order.loadOnce
Order.loadOnce
Order.loadOnce
Order.loadOnce
查看输出显示它只是被调用once
并且不需要加载类。因此,您可以使用以下内容确保在初始化完成之前调用它。
init() { Self.loadOnce }
甚至在打电话之前super.init
override init() {
Self.loadOnce
super.init()
}
推荐阅读
- google-apps-script - 复制数据并将其粘贴到特定范围
- c# - 用右摇杆旋转相机
- ios - 在快速删除 TableViewCell 之前弹出警报用户?
- r - 有没有办法比较两个数据框中具有不同列号的列并删除与某一列不匹配的行?
- r - 非收敛 glmmTMB
- javascript - 为什么这个解决方案不起作用?使用两个地图查找常见字符
- error-handling - SQL Server 代理作业失败处理
- json - jq:基于过滤器的分区
- javascript - 使用 WebAudioAPI 解析和存储音频文件中的音量/dB 数据
- azure-active-directory - 向来宾用户授予存储帐户访问权限(外部 Azure Active Directory)