【问题标题】:Best practice to implement canClose(withDelegate:shouldClose:contextInfo:)实施 canClose(withDelegate:shouldClose:contextInfo:) 的最佳实践
【发布时间】:2018-03-18 00:24:46
【问题描述】:

我第一次尝试使用基于 NSDocument 的应用程序。 (Xcode 9.2、Swift 4、macOS 10.12 Sierra 和 Cocoa/AppKit)

我想知道在没有自动保存的情况下实现关闭文档的正确方法。你能告诉我关闭 NSDocument 的最佳做法吗?

当用户试图关闭文档时,会调用下面的 NSDocument 方法。

canClose(withDelegate:shouldClose:contextInfo:)

我调试了参数,发现followimng:

delegate = MyApp.Document
shouldCloseSelector = _something:didSomething:soContinue:
contextInfo = libsystem_blocks.dylib `_NSConcreteMallocBlock

显然这样的选择器不可用,所以我认为可以在这里更改如下:

override func canClose(withDelegate delegate: Any,
                       shouldClose shouldCloseSelector: Selector?,
                       contextInfo: UnsafeMutableRawPointer?) {
    let delegate : Any = self
    let shouldCloseSelector : Selector = #selector(Document.document(_:shouldClose:contextInfo:))
    super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
}

@objc func document(_ document : NSDocument, shouldClose flag : Bool, 
                    contextInfo: UnsafeMutableRawPointer?) {
    if document === self, flag {
        self.cleanup() // my cleanup method
        self.close() // NSDocument.close()
    }
}

deinit {
    Swift.print(#function, #line)
}

这似乎可行,但我想这不是正确的方法,因为忽略了原始参数(Selector/contextInfo)。

【问题讨论】:

    标签: swift macos


    【解决方案1】:

    更新

    我找到了解决方案。我希望这会对某人有所帮助。

    private var closingBlock : ((Bool) -> Void)? = nil
    
    override func canClose(withDelegate delegate: Any,
                           shouldClose shouldCloseSelector: Selector?,
                           contextInfo: UnsafeMutableRawPointer?) {
        let obj : AnyObject = delegate as AnyObject
        let Class : AnyClass = object_getClass(delegate)!
        let method = class_getMethodImplementation(Class, shouldCloseSelector!)
        typealias signature =
            @convention(c) (AnyObject, Selector, AnyObject, Bool, UnsafeMutableRawPointer?) -> Void
        let function = unsafeBitCast(method, to: signature.self)
    
        self.closingBlock = {[unowned obj, shouldCloseSelector, contextInfo] (flag) -> Void in
            function(obj, shouldCloseSelector!, self, flag, contextInfo)
        }
    
        let delegate : Any = self
        let shouldCloseSelector : Selector = #selector(Document.document(_:shouldClose:contextInfo:))
        super.canClose(withDelegate: delegate, shouldClose: shouldCloseSelector, contextInfo: contextInfo)
    }
    
    @objc func document(_ document : NSDocument, shouldClose flag : Bool,
                        contextInfo: UnsafeMutableRawPointer?) {
        if flag {
            self.cleanup() // my cleanup method
        }
    
        self.closingBlock?(flag)
        self.closingBlock = nil
    }
    
    override func close() {
        Swift.print(#function, #line, #file)
        super.close()
    }
    
    deinit {
        Swift.print(#function, #line, #file)
    }
    

    参考资料

    https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/

    对遵循委托的方法的重写的建议:didSomethingSelector:contextInfo: Pattern

    https://github.com/DouglasHeriot/canCloseDocumentWithDelegate/blob/master/canCloseDocumentWithDelegate/Document.swift

    展示了如何使用 Swift 实现 NSDocument 方法 -canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:。必须使用 Objective-C 来执行 NSInvocation。

    【讨论】:

      猜你喜欢
      • 2015-06-14
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 2011-08-17
      • 2018-10-11
      • 2011-08-22
      相关资源
      最近更新 更多