我正在尝试编写一个简单的闭包作为完成处理程序,并在闭包内设置文本框的文本值:
class ViewController: UIViewController {
@IBOutlet var textArea : UITextView
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session:NSURLSession?
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
session = NSURLSession(configuration: sessionConfig)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
@IBAction func btnSendRequestTapped(sender : AnyObject) {
let url:NSURL = NSURL(string: "https://www.google.com")
let sessionTask:NSURLSessionTask =
session!.dataTaskWithURL(url, completionHandler: {
[unowned self]
(data:NSData!,response:NSURLResponse!,error:NSError!) -> Void in
let st:String = NSString(data: data,encoding: NSUTF8StringEncoding)
println("\(st)")
NSOperationQueue.mainQueue().addOperationWithBlock({
() -> Void in
self.textArea!.text = st
})
})
sessionTask.resume()
}
}
Run Code Online (Sandbox Code Playgroud)
但是在我定义[unowned self]的行上,我得到了EXC_BREAKPOINT(code=EXC_I386_BPT,subcode=0x0),并且它显示了一些汇编代码如下:
libswift_stdlib_core.dylib`_swift_abortRetainUnowned:
0x1001bb980: pushq %rbp
0x1001bb981: movq %rsp, %rbp
0x1001bb984: leaq 0x176a7(%rip), %rax ; "attempted to retain deallocated object"
0x1001bb98b: movq %rax, 0x792ce(%rip) ; gCRAnnotations + 8
0x1001bb992: int3
0x1001bb993: nopw %cs:(%rax,%rax)
Run Code Online (Sandbox Code Playgroud)
根据文档,我不确定我在这里做错了什么.我已经更新了包含全班的问题.此外,我已更新问题,以更新主线程上TextView的文本属性
Mat*_*ros 45
只是为了清楚这里的所有答案 - 你应该如何解决这个错误取决于你的需求.
原始问题中代码的问题在于self,UIViewController从异步执行的NSOperation块访问,这是在异步 的完成处理程序内完成的NSURLSessionTask.
到运行时到达时self.textArea!.text,self已成为nil.在什么情况下会UIViewController被解除分配?当你将它从导航堆栈中弹出,当它被解除时,等等.我猜测btnSendRequestTapped(:)上面的代码是不完整的并且有一个popViewController()地方.
解决方案是:
1:用来weak代替unowned.两者之间的区别在于,这weak意味着捕获的对象(self)可以nil将其转换为可选对象,同时unowned意味着您确定self永远不会,nil并且您可以self按原样访问.使用weak意味着self在使用之前解开.如果它是零,则在代码中不执行任何操作.
{[weak self] in
if let strongSelf = self {
// ...
strongSelf.textArea!.text = "123"
}
}
Run Code Online (Sandbox Code Playgroud)
2:另一种解决方案是,如果从导航堆栈弹出,则取消NSURLSessionTask它的完成处理程序(将被调度到被调用的NSOperationQueue属性中).NSURLSessiondelegateQueueUIViewController
func btnSendRequestTapped() {
// pop the view controller here...
sessionTask.cancel()
sessionTask.delegateQueue.cancelAllOperations()
}
Run Code Online (Sandbox Code Playgroud)
3:继续使用[unowned self],但在操作块完成之前不要弹出视图控制器.我个人更喜欢这种方法.
简而言之,self在实际完成之前不要被解除分配.
我不确定为什么,但我认为它正在使用weak而不是unowned.这可能是一个错误.
session.dataTaskWithURL(url, completionHandler: {
[weak self]
(data:NSData!,response:NSURLResponse!,error:NSError!) -> Void in
let st:String = NSString(data: data,encoding: NSUTF8StringEncoding)
self!.txtArea!.text = "123"
}
)
Run Code Online (Sandbox Code Playgroud)
weak self在这种情况下最好使用,以防万一您从导航堆栈中弹出视图。
更新:Swift 3.0
let task:URLSessionTask = session.dataTask(with: url, completionHandler: {
[weak self] (data:Data?, response: URLResponse?, error:Error?) in
/// Cool tip instead of using *strongSelf*, use ` as:
if let `self` = self {
/// Run your code here, this will ensure if self was deallocated, it won't crash.
}
})
Run Code Online (Sandbox Code Playgroud)
斯威夫特 2.2
let sessionTask:NSURLSessionTask =
session!.dataTaskWithURL(url, completionHandler: {
[weak self] (data:NSData!,response:NSURLResponse!,error:NSError!) -> Void in
/// Cool tip instead of using *strongSelf*, use ` as:
if let `self` = self {
/// Run your code here, this will ensure if self was deallocated, it won't crash.
}
})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20442 次 |
| 最近记录: |