如何在单例类中重新初始化属性?

时间:2017-11-19 17:54:24

标签: swift

我现在面临的问题是每当用户加载应用时。单例对象将运行

单身人士设计

import SocketIO

class SocketIOManager: NSObject {

    static let sharedInstance = SocketIOManager()

    var socket: SocketIOClient!

    override init() {
        socket = SocketIOClient(socketURL: URL(string: mainURL)!, .connectParams(["token": getToken()])])
        super.init()
    }

    func establishConnection() {
       socket.connect()

    }

    func closeConnection() {
        socket.disconnect()
    }

    func getToken() -> String {
      if let token = keychain["token"] {
         return token
      }
        return ""
    }
}

查看init().connectParams,为了让用户连接到服务器,必须存在令牌,因此传递getToken()

如果令牌不存在,它将在没有令牌的情况下初始化套接字对象。我在establishConnection

运行applicationDidBecomeActive
func applicationDidBecomeActive(_ application: UIApplication) {
        SocketIOManager.sharedInstance.establishConnection()
}

只有在用户登录后才会出现令牌。

主要问题是,有没有办法重新初始化套接字对象?或者我使用didSetwillSet方法?

4 个答案:

答案 0 :(得分:1)

也许是这样的?

var socket: SocketIOClient! {
  didSet {
    oldValue.closeConnection()
  }
}

如果你愿意的话,你似乎也可以摆脱!,因为你在init中设置它,假设SocketIOClient.init返回一个非可选实例。

答案 1 :(得分:0)

要做到这一点的一种方法是在SocketIOManager中创建一个公共方法,并使用该方法初始化套接字:

func initializeSocket() {
    socket = SocketIOClient(socketURL: URL(string: mainURL)!, .connectParams(["token": getToken()])])
}

在用户登录后调用此方法。

但顺便说一句,你的初始化程序必须是私有才能正确实现Singleton设计模式。

另一个注意事项是Swift中静态变量的初始化是懒惰的,这意味着它们只在第一次使用时才被初始化。查看此answerSwift documentation on this topic以获取更多信息

答案 2 :(得分:0)

这很简单,你只需要在你的类中声明一个方法:

   func resetConnection() {

            socket.disconnect()
           socket = SocketIOClient(socketURL: URL(string: mainURL)!, .connectParams(["token": getToken()])])
socket.connect()

        }

并在以下

中使用
SocketIOManager.sharedInstance.resetConnection()
let socket =  
SocketIOManager.sharedInstance.socket // this will be the newer 

答案 3 :(得分:0)

首先,你是从AppDelegate调用这个流程,这是你依赖这个令牌存在的问题。所以我在这里跳出来的是你错过了一个方法,在启动连接之前检查这个令牌是否真的存在,如果你不能生成令牌,该方法应该完全放弃连接套接字(也就是说,如果您的连接实际上是令牌依赖的,如果不是,那么之前的答案应该可以帮助您。)

由于您在管理器类的init覆盖范围内初始化套接字是正确的,因此它违背了我认为您想要的内容,即一旦令牌成为存在,就会重置连接。最初不在那里。为此,如上所述,你应该停止创建套接字。

我通常为单身人士做的事情:我给他们一个空白"配置"方法,将其提交到内存,通常在AppDelegate的establishConnection上。如果此方法包含任何内容,则会检查单例依赖的任何值的方法,并根据这些值(如某些枚举情况)为单例分配自定义内部状态。然后我会像你在这里一样调用establishConnection,但appDidEnterForeground应该是一个可以在每个import SocketIO enum SocketIOManagerState { case invalidURL case launched case tokenNotPresent case manuallyDisconnected case backgroundedByOS } class SocketIOManager: NSObject { private var state : SocketIOManagerState = SocketIOManagerState.launched private var staticSocketURL : URL? static let sharedInstance = SocketIOManager() var socket: SocketIOClient? override init() { super.init() } func configure() { //fetch the url string from wherever and apply it to staticSocketURL guard let url = URL(string: "The URL from wherever") else { state = SocketIOManagerState.invalidURL return } if getToken() == nil { state = .tokenNotPresent } else { //only here can we be sure the socket doesn't have any restrictions to connection staticSocketURL = url state = SocketIOManagerState.launched } } func evaluateConnection() { guard let token = getToken() else { //maybe something went wrong, so make sure the state is updated if socket != nil { return evaluateSocketAsNotNil() } return closeConnection(true, .tokenNotPresent) } switch state { case .tokenNotPresent, .invalidURL: closeConnection(true) break case .launched: //means token was present, so attempt a connection guard socket == nil else { evaluateSocketAsNotNil() return } guard let url = staticSocketURL else { //maybe something went wrong with the url? so make sure the state is updated. if socket != nil { return closeConnection(true, .invalidURL) } return setState(.invalidURL) } if socket == nil { socket = SocketIOClient(socketURL: url, .connectParams(["token": token])) } socket?.connect() default: //unless you care about the other cases, i find they all fall back on the same logic : we already checked if the token is there, if we get here, it means it is, so should we reconnect? guard weCanReconnect /*some param or method which you create to determine if you should*/ else { //you determine you should not, so do nothing return } //you determine you do, so: } } private func evaluateSocketAsNotNil() { guard let sock = socket else { return } switch sock.state { case .notConnected: //evaluate if it should be connected establishConnection() case .disconnected: evaluateSocketAsNotNil() case .connecting: //do nothing perhaps? case connected: guard getToken() != nil else { //token is not present, but the socket is initialized, this can't happen so disconnect and reset the instance closeConnection(true, .tokenNotPresent) return } break //nothing to do here } } private func establishConnection() { guard let sock = socket else { return } sock.connect() } func setState(_ to: SocketIOManagerState) { self.state = to } func closeConnection(_ clearMemory: Bool) { guard let sock = socket else { return } sock.disconnect() setState(.launched) if clearMemory { socket = nil } } private func closeConnection(_ clearMemory: Bool,_ to: SocketIOManagerState) { socket?.disconnect() setState(to) if clearMemory { socket = nil } } func getToken() -> String? { guard let token = keychain["token"] else { state = .tokenNotPresent return nil } return token } } 方法运行的泛型方法,但不必担心改变事情,它应该重新建立事物当你的应用程序被落后时被删除了。

所以我建议你改变你的课程:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        SocketIOManager.sharedInstance.configure()

        return true
    }


    func applicationDidEnterBackground(_ application: UIApplication) {
        SocketIOManager.sharedInstance.closeConnection(false, .backgroundedByOS)
    }


    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

        SocketIOManager.sharedInstance.evaluateConnection()
    }

然后你的AppDelegate看起来像这样:

evaluateConnection()

从这里开始,您随时可以在应用中的其他任何位置调用closeConnection(_:, _:)evaluateConnection,并添加更多状态案例,以及更多以逻辑方式处理这些案例的方法。无论哪种方式,您都可以根据令牌确定应该如何连接和重新连接。

使用此结构,如果您的用户登录,并且您在应用中正确设置了令牌,那么您应该能够在登录过程中调用map时正确连接套接字。 还有很多评论,有些事情似乎是通用的(道歉),但是由您来填写用例的空白。

希望它有所帮助!