I have 2 windows in swift, one is like a login dialog which sends an NSURLConnection.sendAsynchronousRequest to a server to get authenticated. Once it gets the response, the window is supposed to close.
When I close the Window (either from the login window class or main window clasS) I get these errors:
This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.
I have tried all manner of background threads etc. But I think the issue is that I am closing the window why the asynch NSURLConnection request is still hanging.
My code to send the async request from the login window:
dispatch_async(dispatch_get_main_queue(), {
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
let result: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
let expectedString = "special auth string"!
if(result == expectedString) {
self.callback.loginOK()
} else {
self.output.stringValue = result
}
return
})
})
The callback member of the class is the parent view contoller that spawns it, I then close the login window using loginVC.view.window?.close() from the main application window. That causes the error.
The problem is that NSURLConnection.sendAsynchronousRequest will always run in a secondary thread and thus its callback will be called from that secondary thread despite you calling it explicitly from main thread.
You don't need to wrap NSURLConnection.sendAsynchronousRequest in the main thread, instead wrap your ' self.callback.loginOK()' to run in main thread using the dispatch_async to ensure no UI related operations take place in secondary thread. Something like this-
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
let result: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
dispatch_async(dispatch_get_main_queue() {
let expectedString = "special auth string"!
if(result == expectedString) {
self.callback.loginOK()
} else {
self.output.stringValue = result
}
})
return
})
Related
I am using AFNetworking to parse some data and then save to CoreData, I want to do something like this.
let parserContext: NSManagedObjectContext = MTCoreDataManager.sharedManager().newPrivateManagedObjectContext()
let mainContext: NSManagedObjectContext = MTCoreDataManager.sharedManager().managedObjectContext()
override func responseObjectForResponse(response: NSURLResponse!, data: NSData!, error: NSErrorPointer) -> AnyObject? {
var model: NSManagedObject?
parserContext.performBlockAndWait {
....parsing data...
....create model and assign value...
....save model...
let objID = model.objectID
mainContext.performBlockAndWait {
model = mainContext.objectWithID(objID)
}
}
return model
}
let op = AF.GET(path, parameters: nil, success: { (operation: AFHTTPRequestOperation, response: AnyObject) -> Void in
// main thread
println(response)
}) { (operation: AFHTTPRequestOperation, error: NSError) -> Void in
println(error.description)
}
As responseObjectForResponse runs in a background thread, I want to use a background context to parse the data and create the NSManagedObject in that context, and then get back the object in main thread as the final callback will be on the main thread, I don't want to return the NSManagedObjectID, I want to return the NSManagedObject but I don't know if this is safe.
Is it safe? I don't think it is.
Instead you should create a child context in the completion block and do all your Core Data saving within a block.
childContext.performBlockAndWait() {
// parse, insert and save
}
Remember that saving will just "push" the changes up to the main context. You will still have to save them to the persistent store. The main context should be aware of any changes automatically (via a NSFetchedResultsControllerDelegate or NSNotificationCenter).
I have an additional convenience method in my data manager class (or app delegate) to save the data to the persistent store, similar to the plain vanilla saveContext method provided by the Apple templates. This should a method that can be called safely from anywhere by also using above block API to save the context.
I have a function which calls Concurrency::create_task to perform some work in the background. Inside that task, there is a need to call a connectAsync method on the StreamSocket class in order to connect a socket to a device. Once the device is connected, I need to grab some references to things inside the connected socket (like input and output streams).
Since it is an asynchronous method and will return an IAsyncAction, I need to create another task on the connectAsync function that I can wait on. This works without waiting, but complications arise when I try to wait() on this inner task in order to error check.
Concurrency::create_task( Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService::FromIdAsync( device_->Id ) )
.then( [ this ]( Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService ^device_service_ )
{
_device_service = device_service_;
_stream_socket = ref new Windows::Networking::Sockets::StreamSocket();
// Connect the socket
auto inner_task = Concurrency::create_task( _stream_socket->ConnectAsync(
_device_service->ConnectionHostName,
_device_service->ConnectionServiceName,
Windows::Networking::Sockets::SocketProtectionLevel::BluetoothEncryptionAllowNullAuthentication ) )
.then( [ this ]()
{
//grab references to streams, other things.
} ).wait(); //throws exception here, but task executes
Basically, I have figured out that the same thread (presumably the UI) that creates the initial task to connect, also executes that task AND the inner task. Whenever I attempt to call .wait() on the inner task from the outer one, I immediately get an exception. However, the inner task will then finish and connect successfully to the device.
Why are my async chains executing on the UI thread? How can i properly wait on these tasks?
In general you should avoid .wait() and just continue the asynchronous chain. If you need to block for some reason, the only fool-proof mechanism would be to explicitly run your code from a background thread (eg, the WinRT thread pool).
You could try using the .then() overload that takes a task_options and pass concurrency::task_options(concurrency::task_continuation_context::use_arbitrary()), but that doesn't guarantee the continuation will run on another thread; it just says that it's OK if it does so -- see documentation here.
You could set an event and have the main thread wait for it. I have done this with some IO async operations. Here is a basic example of using the thread pool, using an event to wait on the work:
TEST_METHOD(ThreadpoolEventTestCppCx)
{
Microsoft::WRL::Wrappers::Event m_logFileCreatedEvent;
m_logFileCreatedEvent.Attach(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
long x = 10000000;
auto workItem = ref new WorkItemHandler(
[&m_logFileCreatedEvent, &x](Windows::Foundation::IAsyncAction^ workItem)
{
while (x--);
SetEvent(m_logFileCreatedEvent.Get());
});
auto asyncAction = ThreadPool::RunAsync(workItem);
WaitForSingleObjectEx(m_logFileCreatedEvent.Get(), INFINITE, FALSE);
long i = x;
}
Here is a similar example except it includes a bit of Windows Runtime async IO:
TEST_METHOD(AsyncOnThreadPoolUsingEvent)
{
std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
int i;
auto workItem = ref new WorkItemHandler(
[_completed, &i](Windows::Foundation::IAsyncAction^ workItem)
{
Windows::Storage::StorageFolder^ _picturesLibrary = Windows::Storage::KnownFolders::PicturesLibrary;
Concurrency::task<Windows::Storage::StorageFile^> _getFileObjectTask(_picturesLibrary->GetFileAsync(L"art.bmp"));
auto _task2 = _getFileObjectTask.then([_completed, &i](Windows::Storage::StorageFile^ file)
{
i = 90210;
_completed->set();
});
});
auto asyncAction = ThreadPool::RunAsync(workItem);
_completed->wait();
int j = i;
}
I tried using an event to wait on Windows Runtime Async work, but it blocked. That's why I had to use the threadpool.
I'm trying to update my UI while executing a function with a status closure and a completion closure. The UI is only updated when the closure is complete. I understand that this happens because the operation is not happening on the main thread and the UI need to be updated on the main thread. I have tried moving the UI updates to the main thread, but without any luck. I have included a simplified version of my code.
How can I solve this problem? Will it solve the problem if I specify a custom thread for my code to be excecuted? If so, how is that done?
Thank you very much for taking your time to read.
Code is included below. Let me know if you need any more information regarding this issue.
func parse(array: [String], status:(status: String!, progress: Float!) -> (), completion:(result: [String]!) ->()) -> () {
status(status: "Process is starting.", progress: 0)
var newArray = [String]()
for (index, txt) in enumerate(array) {
//Update status
let progress = Float(index + 1) / Float(array.count)
status(status: "Checking string: \(txt)", progress: progress)
//Do something with txt
let newTxt = txt + "OK"
newArray.append(newTxt)
}
status(status: "Complete!", progress: 1.0)
//Send completion
completion(result: newArray)
}
var startArray = [String]()
for index in 0...10000 {
startArray.append("\(index)")
}
parse(startArray, { (status: String!, progress: Float!) -> () in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println(status)
self.statusLabel.text = status
println(progress)
self.progressView.progress = progress
})
}, { (result: [String]!) -> () in
println("Process complete. Here is the result:\n\(result)")
})
My problem was that parse was called on the main thread, so when updating the UI, that thread was already blocked. I solved the problem (with the help of David's comments) by putting parse in another thread, then updating the UI on the main thread with GCD.
I'm trying to create my first app in Swift which involves making multiple requests to a website. These requests are each done using the block
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in ... }
task.resume()
From what I understand this block uses a thread different to the main thread.
My question is, what is the best way to design code that relies on the values in that block? For instance, the ideal design (however not possible due to the fact that the thread executing these blocks is not the main thread) is
func prepareEmails() {
var names = getNames()
var emails = getEmails()
...
sendEmails()
}
func getNames() -> NSArray {
var names = nil
....
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
names = ...
})
task.resume()
return names
}
func getEmails() -> NSArray {
var emails = nil
....
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
emails = ...
})
task.resume()
return emails
}
However in the above design, most likely getNames() and getEmails() will return nil, as the the task will not have updated emails/name by the time it returns.
The alternative design (which I currently implement) is by effectively removing the 'prepareEmails' function and doing everything sequentially in the task functions
func prepareEmails() {
getNames()
}
func getNames() {
...
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
getEmails(names)
})
task.resume()
}
func getEmails(names: NSArray) {
...
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
sendEmails(emails, names)
})
task.resume()
}
Is there a more effective design than the latter? This is my first experience with concurrency, so any advice would be greatly appreciated.
The typical pattern when calling an asynchronous method that has a completionHandler parameter is to use the completionHandler closure pattern, yourself. So the methods don't return anything, but rather call a closure with the returned information as a parameter:
func getNames(completionHandler:(NSArray!)->()) {
....
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {data, response, error -> Void in
let names = ...
completionHandler(names)
}
task.resume()
}
func getEmails(completionHandler:(NSArray!)->()) {
....
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {data, response, error -> Void in
let emails = ...
completionHandler(emails)
}
task.resume()
}
Then, if you need to perform these sequentially, as suggested by your code sample (i.e. if the retrieval of emails was dependent upon the names returned by getNames), you could do something like:
func prepareEmails() {
getNames() { names in
getEmails() {emails in
sendEmails(names, emails) // I'm assuming the names and emails are in the input to this method
}
}
}
Or, if they can run concurrently, then you should do so, as it will be faster. The trick is how to make a third task dependent upon two other asynchronous tasks. The two traditional alternatives include
Wrapping each of these asynchronous tasks in its own asynchronous NSOperation, and then create a third task dependent upon those other two operations. This is probably beyond the scope of the question, but you can refer to the Operation Queue section of the Concurrency Programming Guide or see the Asynchronous vs Synchronous Operations and Subclassing Notes sections of the NSOperation Class Reference.
Use dispatch groups, entering the group before each request, leaving the group within the completion handler of each request, and then adding a dispatch group notification block (called when all of the group "enter" calls are matched by their corresponding "leave" calls):
func prepareEmails() {
let group = dispatch_group_create()
var emails: NSArray!
var names: NSArray!
dispatch_group_enter(group)
getNames() { results in
names = results
dispatch_group_leave(group)
}
dispatch_group_enter(group)
getEmails() {results in
emails = results
dispatch_group_leave(group)
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
if names != nil && emails != nil {
self.sendEmails(names, emails)
} else {
// one or both of those requests failed; tell the user
}
}
}
Frankly, if there's any way to retrieve both the emails and names in a single network request, that's going to be far more efficient. But if you're stuck with two separate requests, you could do something like the above.
Note, I wouldn't generally use NSArray in my Swift code, but rather use an array of String objects (e.g. [String]). Furthermore, I'd put in error handling where I return the nature of the error if either of these fail. But hopefully this illustrates the concepts involved in (a) writing your own methods with completionHandler blocks; and (b) invoking a third bit of code dependent upon the completion of two other asynchronous tasks.
The answers above (particularly Rob's DispatchQueue based answer) describe the concurrency concepts necessary to run two tasks in parallel and then respond to the result. The answers lack error handling for clarity because traditionally, correct solutions to concurrency problems are quite verbose.
Not so with HoneyBee.
HoneyBee.start()
.setErrorHandler(handleErrorFunc)
.branch {
$0.chain(getNames)
+
$0.chain(getEmails)
}
.chain(sendEmails)
This code snippet manages all of the concurrency, routes all errors to handleErrorFunc and looks like the concurrent pattern that is desired.
What is the best way to accomplish the following in a web page lifecycle?
protected void btnTestAsync_Click(object sender, EventArgs e)
{
this.MainThreadID = Thread.CurrentThread.ManagedThreadId;
TestBLL bl = new TestBLL();
bl.OnBeginWork += OnBeginWork;
bl.OnEndWork += OnEndWork;
bl.OnProgressUpdate += OnWork;
ThreadStart threadDelegate = new ThreadStart(bl.PerformBeginWork);
Thread newThread = new Thread(threadDelegate);
newThread.Start();
}
Then on the OnWorkEvent I enter:
private void OnWork(AsyncProgress workProgress, ref bool abortProcess)
{
string s = String.Format("MAIN TREAD: {0} WORKER THREAD: {1} COUNT :{2} COMPLETE: {3} REMAINING: {4}",
this.MainThreadID,
workProgress.ThreadID,
workProgress.NumberOfOperationsTotal,
workProgress.NumberOfOperationsCompleted,
workProgress.NumberOfOperationsRemaining);
lbl.Text = s;
lb.Items.Add(s);
//.ProcessMessages(); Response.Redirect???<-- Here I want to rfresh the page. During debug the test variables are proper
}
Please excuse my ignorance; I have never done this with a Web.UI.Page. What is the best way to update the UI from a delegate callback in another thread?
Thanks,
I would suggest ajax.
Your button click will cause a browser postback. From that point there is nothing really to "force" the browser (client side) to do another postback unless the user "does something"
Using ajax you can do an async call that will respond when the call is complete.
There are multiple ways to do this, but i personally use jquery.
here is an example of a possible ajax call using jquery:
$.ajax({
url: "../ajax/backgroundworker.ashx",
data: 'element=' + $(this).parent().siblings('.datarow').children('.dataelement').text(),
dataType: "text",
success: function(data) {
var taData = data.split("|");
if (taData[0] != "-1") {
$(".dataelement:contains('" + taData[0] + "')").parent().siblings().children('.displayfield').text(taData[1]);
$(".dataelement:contains('" + taData[0] + "')").parent().siblings().children('.img_throbber').css('visibility', 'hidden');
}
else {
alert("There is currently a problem accessing the background service that is responsible for data processing.");
$('.do_work_button').css("visibility", "hidden");
$(".dataelement").parent().siblings().children('.dataelement').text("N/A");
$(".dataelement").parent().siblings().children('.img_throbber').css('visibility', 'hidden');
}
},
error: function(xhr, status, error) {
displayAjaxError(xhr);
$(".dataelement").parent().siblings().children('.img_throbber').css('visibility', 'hidden');
}
the $.ajax command is called with a click event on your page. and the .ashx (asp.net web handler file) is kinda like the vehichle you can use to get data from your client side to server side. you can reference server side objects and code in the .ashx that use the data from the client side ajax call to return results via the http context.