在swift代码崩溃:“无法识别的选择器发送到实例”
问题描述:
我想写一个命令行Swift应用程序,使HTTP请求。作为一个方面说明,我想提供一个会话到应用程序的run
函数,以便我可以使用依赖注入来单元测试代码(因此我定义的协议)。在swift代码崩溃:“无法识别的选择器发送到实例”
这会与“无法识别的选择器发送到实例”崩溃。这是什么意思?
//
// main.swift
// MockIt
//
//
import Foundation
public protocol URLSessionProtocol {
func synchronousDataTask(_ url: URL) -> (Data?, URLResponse?, Error?)
}
class MyUrlSession : URLSession, URLSessionProtocol {
func synchronousDataTask(_ url: URL) -> (Data?, URLResponse?, Error?) {
var data: Data?
var response: URLResponse?
var error: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = self.dataTask(with: url) {
data = $0
response = $1
error = $2
semaphore.signal()
}
dataTask.resume()
_ = semaphore.wait(timeout: .distantFuture)
return (data, response, error)
}
}
class MyModule {
func run(_ session: URLSessionProtocol, _ urlString: String) {
let url = URL(string: urlString)
let (_, response, _) =
session.synchronousDataTask(url!)
print(response!)
}
}
MyModule().run(MyUrlSession(), "https://myapiendpoint.com")
完整的崩溃是在这里:
2017-04-12 11:29:07.930076 MockIt[33267:1871173] -[MockIt.MyUrlSession dataTaskForRequest:completion:]: unrecognized selector sent to instance 0x100a043d0
2017-04-12 11:29:07.933897 MockIt[33267:1871173] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MockIt.MyUrlSession dataTaskForRequest:completion:]: unrecognized selector sent to instance 0x100a043d0'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff785dfe7b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00007fff8d1c0cad objc_exception_throw + 48
2 CoreFoundation 0x00007fff78661cb4 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x00007fff78551fb5 ___forwarding___ + 1061
4 CoreFoundation 0x00007fff78551b08 _CF_forwarding_prep_0 + 120
5 MockIt 0x000000010000177d _TFC6MockIt12MyUrlSession19synchronousDataTaskfV10Foundation3URLTGSqVS1_4Data_GSqCSo11URLResponse_GSqPs5Error___ + 477
6 MockIt 0x0000000100001bf8 _TTWC6MockIt12MyUrlSessionS_18URLSessionProtocolS_FS1_19synchronousDataTaskfV10Foundation3URLTGSqVS2_4Data_GSqCSo11URLResponse_GSqPs5Error___ + 72
7 MockIt 0x0000000100001d1d _TFC6MockIt8MyModule3runfTPS_18URLSessionProtocol_SS_T_ + 253
8 MockIt 0x0000000100001584 main + 116
9 libdyld.dylib 0x00007fff8daa4255 start + 1
10 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
不知道它的问题,但是这是我的应用程序目录的一般结构:
$ tree -L 2
.
├── DerivedData
│ ├── Build
│ ├── MockIt
│ └── ModuleCache
├── MockIt
├── MockIt-Bridging-Header.h
├── MockIt.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ └── xcuserdata
├── MockItTest
│ ├── Info.plist
│ └── MockItTest.swift
└── main.swift
答
URLSession
没有设计成被分类。
我认为你看到的问题源于你没有完全初始化URLSession
子类的事实。你打电话init()
,URLSession
意味着至少通过init(configuration:)
配置对象初始化。
你不能从子类中自己调用这些初始化程序,因为它们被特别标记为不可继承。
你不能自己分配给配置属性,因为它是一个只读的。
你也许可以通过覆盖属性来绕过这个方法,但是不要继承URLSession
就更好了。你有没有考虑过把它当做扩展呢?
还有一点点在this question信息。