对于Mac OS 10.11及更高版本,我拥有大量的Swift 3代码(使用Xcode 8.2.1)。有许多过程,其中包括GUI应用程序和后台服务。两者都使用自定义的URLProtocol,该代码在框架中实现(由应用程序和服务导入)。该协议(protocol)有时可能会生成符合enumError实例,并会对其进行适当的捕获和处理(通常通过使用URLProtocolClient将其扔到尝试提出请求的URLSession上)。

  • 如果没有错误,则应用程序和服务都可以正常工作。
  • 出现错误时,该应用程序运行正常(按预期方式运行)。
  • 出现错误时,服务将崩溃

  • 在调试器中徘徊显示,当运行时Error自动转换为NSError时,将发生此崩溃。我在代码中明确地添加了这个强制类型转换,并且肯定的是,现在我在同一行上遇到了同样的崩溃。

    我看到了Swift 3.1: Crash when custom error is converted to NSError to access its domain property,但不适用于这里:
  • 那里的解决方案-将Error扩展为CustomNSError(以及LocalizedError作为很好的措施)并实现相关属性-没有帮助。
  • 获取domain后发生崩溃。据我所知,这对我来说不是问题。
  • 可能相关:在iOS而非Mac上。

  • 已经尝试过列出该问题的唯一解决方案后,我有些茫然。我已经调试了好几个小时,却无所事事,只是它似乎发生在dyld的深处。

    码:
    enum CrowbarProtocolError: Error {
        case FailedToCreateSocket;
        case PathTooLong;
        case NonSocketFile;
        case SocketNotFound;
    ...
        case UnrecognizedError(errno: Int32);
    }
    extension CrowbarProtocolError: LocalizedError {
        public var errorDescription: String? {
            return "Some localized description"
        }
    }
    extension CrowbarProtocolError: CustomNSError {
        public static var errorDomain: String {
            return "Some Domain Name"
        }
        public var errorCode: Int {
            return 204 //Should be your custom error code.
        }
        public var errorUserInfo: [String: Any] {
            return ["WTF": "Swift?"];
        }
    }
    ...
    open class CrowbarUrlProtocol: URLProtocol  {
    ...
        override open func startLoading() {
            do {
                let sockHandle = try CrowbarUrlProtocol.openSocket();
                let req = try buildRequestData();
                sockHandle.write(req);
                NotificationCenter.default.addObserver(
                    self,
                    selector: #selector(self.readCompleted),
                    name: .NSFileHandleReadToEndOfFileCompletion,
                    object: nil);
                sockHandle.readToEndOfFileInBackgroundAndNotify();
            } catch let err {
                Log.warn("CrowbarUrlProtocol request failed with error \(err)");
                // -- In the background service, THIS LINE CRASHES! --
                let err2 = err as NSError;
                Log.warn("As NSError: \(err2)");
                // -- Without the explicit cast, it crashes on this line --
                self.client?.urlProtocol(self, didFailWithError: err);
            }
        }
    ...
    }
    

    解决这个问题的一个主意是使用NSError进行所有(或尽可能多的)操作,理由是,如果永远不需要将Error转换为NSError,那么导致崩溃的任何原因都不会发生。不知道它是否可以工作,但似乎值得一试...

    最佳答案

    好的,据我所知这只是Swift运行时的一个错误,但我找到了一种解决方法:对涉及Obj-C代码的所有内容都使用NSError而不是Swift Error(以避免隐式强制转换)。因为我已经实现了CustomNSError,所以很容易在我的toNSError()枚举上创建一个Error函数,并将其用于self.client?.urlProtocol(self, didFailWithError: err)行。

    enum CrowbarProtocolError: Error, CustomNSError {
        case FailedToCreateSocket;
        case PathTooLong;
    ...
        public func asNSError() -> NSError {
            return NSError(domain: CrowbarProtocolError.errorDomain,
                        code: self.errorCode,
                        userInfo: self.errorUserInfo);
        }
    }
    ...
    open class CrowbarUrlProtocol: URLProtocol  {
    ...
        override open func startLoading() {
            do {
                let sockHandle = try CrowbarUrlProtocol.openSocket();
                let req = try buildRequestData();
                sockHandle.write(req);
                NotificationCenter.default.addObserver(
                    self,
                    selector: #selector(self.readCompleted),
                    name: .NSFileHandleReadToEndOfFileCompletion,
                    object: nil);
                sockHandle.readToEndOfFileInBackgroundAndNotify();
            } catch let err as CrowbarProtocolError {
                Log.warn("CrowbarUrlProtocol request failed with error \(err)");
                self.client?.urlProtocol(self, didFailWithError: err.asNSError());
            }
            catch let err {
                Log.warn("CrowbarUrlProtocol caught non-CrowbarProtocol Error \(err)");
                // This would probably crash the service, but shouldn't ever happen
                self.client?.urlProtocol(self, didFailWithError: err);
            }
        }
    ...
    }
    

    关于swift - 将Error转换为NSError时,Swift 3自定义URLProtocol崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43859552/

    10-11 19:10