带有throwable初始化程序的单例

时间:2017-11-17 09:51:41

标签: swift

我有一个单身人士:

public class Manager {
  static let shared = Manager()
  private init() {
    ...
  }
}

其他类可以通过以下方式访问它:

Manager.shared

这里没问题。现在,我开始思考,如果私有初始化程序是可抛出的,该怎么办?

public class Manager {
   // Compiler error: Call can throw, but erros cannot be thrown out of global variable initializer 
   static let shared = Manager()

   // throwable initialier
   private init() throws {
     ...
   }
}

如果我仍然希望Manager成为单身人士,如何解决上述错误?

3 个答案:

答案 0 :(得分:3)

许多可能的解决方案之一可能是让共享变量为Optional并使用try?关键字调用初始值设定项。

像这样:

public class Manager {
   static let shared: Manager? = try? Manager()

   // throwable initialier
   private init() throws {
     ...
   }
}

编辑: 如果您想在上次调用init时失败,尝试重新创建对象,则可以编写类似这样的内容。

public class Manager {
    static var shared: Manager? {
        get {
            if instance == nil {
                instance = try? Manager()
            }
            return instance
        }
    }

    static private var instance: Manager? = try? Manager()

    // throwable initialier
    private init() throws {
        ...
    }
}

答案 1 :(得分:1)

你看到的错误很清楚。如果您不理解,我建议您阅读投掷函数的文档here

有几种方法可以解决这个问题,问题是 - 为什么你会为单例对象抛出标记初始化器...你可以做的一件事就是将初始化器包装成setupManager函数,就像这样:

public class Manager {

    static let shared = setupManager()

    // throwable initialier
    private init() throws {

    }

    static func setupManager() -> Manager {

        do {

            return try Manager()
        } catch let error {

            fatalError("error:\(error)")
        }
    }
}

在没有设置方法的较短声明中:

public class Manager {

    static var shared: Manager {

        do {

            return try Manager()
        } catch let error {
            // Immediatly stops program execution...
            fatalError("An error occured: \(error)")
        }
    }

    // throwable initialier
    private init() throws {

    }
}

解决这个问题的另一种方法是使用try?并使共享实例可选(在我上面发布的文档中找到):

public class Manager {

    static let shared: Manager? = try? Manager()

    // throwable initialier
    private init() throws {

    }
}

其他方面可能是强制解开它,但这不是你想要做的,因为它对问题的解决方法非常糟糕......

请记住,总是当你编写代码时,修复问题的核心,而不是症状,它总是会变得更糟。在任何情况下,我都没有看到任何使单身初始化器抛出的原因,所以如果您依赖于应用程序中应该交给它的一些代码,请重新考虑您的体系结构。欢迎提出问题。祝你编码愉快!

答案 2 :(得分:0)

获取单例实例意味着您不知道它是否已经启动。如果它的throwable意味着你想跟踪。

这里有一个你可以遵循的解决方案。

enum SomeError: Error {
    case unknown
}

public class Manager {
    private static var sharedManger: Manager? = {
        do {
            let manager = try Manager()
            return manager
        } catch {
            return nil
        }
    }()
    private init() throws {
        ...
    }

    class func shared() throws -> Manager {
        if let sm = sharedManger {
            return sm
        } else {
            throw SomeError.unknown
        }
    }
}

现在你可以做类似

的事情了
do {
    try Manager.shared()
} catch {
    print("Throw")
}