barnabus
barnabus

Reputation: 882

Asynchronous block call to self crashes with EXC_BAD_ACCESS in Swift

I have an API call (using AFNetworking) that when fails calls a failure block. This block simply stop the table view refresh controller via 'self.refreshController.stopRefreshing(); However at run-time this causes a EXC_BAD_ACCESS error.

failure: { (error: NSError!, reason: String!) -> Void in
                self.refreshController.endRefreshing()
        }

I've tried putting the call in a 'dispatch_async' main queue but the call is already on the Main queue and the same error arises.

failure: { (error: NSError!, reason: String!) -> Void in
                dispatch_async(dispatch_get_main_queue())
                {
                    self.refreshController.endRefreshing()
                }
        }

This leads me to believe the issue is to do with a pointer to 'self' at the time the failure block is called... I've tried 'weak' and 'unowned' self but these don't resolve it.

failure: { [weak self] (error: NSError!, reason: String!) -> Void in
                self?.refreshController.endRefreshing()
        }      

Any thoughts would be welcome.

UPDATE: Initialisaton

class ResultsViewController: UIViewController, UITableViewControllerDelegate, UITableViewControllerDataSource 
{ 
    var refreshController = UIRefreshControl() 

    override func viewDidLoad() 
    { 
        super.viewDidLoad() 
        // pull-to-refresh setup                  
        self.refreshController.addTarget(self, action: "refreshTable:", forControlEvents: UIControlEvents.ValueChanged) 
        self.tableView.addSubview(self.refreshController) 
    } 
}

Upvotes: 0

Views: 1369

Answers (1)

barnabus
barnabus

Reputation: 882

Eventually found the root cause.

I was using AFNetworking for API calls and had created a custom Failure block which included the reason if the API call failed. This was up the chain in the call stack but this error seemed to mask it. None of the above methods were required, but using the weak self method did help the compiler surface the issue in the right file.

The issue could be traced back to the here:

Two block type aliases

typealias SuccessBlock = (responseArray: AnyObject!) -> Void
typealias FailureBlock = (error: NSError, reason: String) -> Void

AFNetworking POST call

private func post(url: String, inout parameters: [String : AnyObject], success: SuccessBlock, failure: FailureBlock)
{
    self.sessionManager.POST(url,
        parameters: parameters,
        success: { (operation: NSURLSessionDataTask!, responseObject: AnyObject!) -> Void in
            println("DEBUG: API POST Request to \(url) successful.")
            var responses = responseObject as? [AnyObject]
            success(responseArray:responses)
        },
        failure: { (operation: NSURLSessionDataTask!, error: NSError!) -> Void in
            let reason = self.getResponseReasonFromError(error)
            println("DEBUG: API GET Request to \(url) \nFailed: \(error). \nAPI Response: \(reason)")
            failure(error: error, reason: reason)
        }
    )
}

Error was here in the FailureBlock type alias

typealias FailureBlock = (error: NSError, reason: String) -> Void
typealias FailureBlock = (error: NSError, reason: String!) -> Void

Missing a ! after String.

Upvotes: 1

Related Questions