我有一个viewController使用DownloaderDelegate协议与DownloaderHandler进行通信。
我的协议定义为:
protocol DownloaderDelegate : class {
func didReceive(data:Data)
}
我有一个viewController
class ViewController: UIViewController {
weak var downloadHandler : DownloaderHandler?
override func viewDidLoad() {
super.viewDidLoad()
downloadHandler = DownloaderHandler()
downloadHandler?.delegate = self
changeBackground()
}
func changeBackground (){
let googleURL = URL(fileURLWithPath: "https://www.google.com/doodle4google/images/splashes/featured.png")
print(googleURL)
downloadHandler?.downloadData(url:googleURL) // Line BB
}
}
extension ViewController : DownloaderDelegate{
func didReceive(data: Data) {
let image = UIImage(data: data)
let imageView = UIImageView(image: image!)
view.insertSubview(imageView, at: 0)
}
}
我有一个委托课程:
class DownloaderHandler : NSObject, URLSessionDelegate{
weak var delegate :DownloaderDelegate?
var downloadsSession: URLSession = {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
return session // Line AA
}()
func downloadData(url: URL){ // Line CC
downloadsSession.dataTask(with: url){ data, response, error in
print("error is \(error), data is \(data) and response is \(response)") // Line DD
if let badError = error {
print(" the url didn't succeeed error is \(badError.localizedDescription)")
}
else if let someResponse = response as? HTTPURLResponse {
if someResponse.statusCode == 200{
self.delegate?.didReceive(data: data!)
}
}
}
}
}
使用断点:行AA,加载。线路BB呼叫。线CC永远不会被调用。为什么?我究竟做错了什么?!
答案 0 :(得分:4)
您已声明:
weak var downloadHandler : DownloaderHandler?
然后你说:
downloadHandler = DownloaderHandler()
downloadHandler
是weak
引用,没有其他任何内容保留此DownloaderHandler实例,因此它在创建后会在一团烟雾中消失。您的日志记录显示它正在创建,但如果您要登录其deinit
,您也会看到它立即消失。当您说downloadHandler?.downloadData(url:googleURL)
时,您的downloadHandler
引用为nil
,因此没有任何反应;那时你正在和没人说话。
[你可能会盲目地遵循一个心理规则,委托引用应该是弱的。但是这个规则是基于代表具有独立存在的假设,因此不应该拥有"拥有"由推荐人。然而,这个对象没有独立存在;它更像是一个装饰对象(我称之为助手)。因此,参考需要很强。反向引用仍然很弱,因此您不会获得循环保留周期。]
答案 1 :(得分:1)
删除"弱"来自视图控制器上的downloadHandler属性的限定符。
由于它是对downloadHandler对象的唯一引用,因此只要viewDidLoad方法完成执行,它就会从内存中删除。
你可以做一个小测试;在BB行添加一个断点,检查downloadHandler是否有值。我怀疑它会是" nil",因为它是一个弱小的属性。