首页 > 解决方案 > IOS Swift:在init方法(构造函数)之前运行一次代码块

问题描述

在 IOS SWIFT 中,如何实现类似于C# 中提供的静态构造函数的类似功能。

那是:

  1. 在 init 方法之前执行一段代码(在类中执行的第一个代码块)
  2. 自动调用
  3. 在类的生命周期中只执行一次

这是为了设置一个全局转换映射,以使用提供的名称而不是真实的类名(类名是“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*

标签: iosswift

解决方案


有一个名为的类方法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()
}

推荐阅读