I am struggeling with something and I would like to ask you if you could point me in the right direction.
I have four tasks I want to complete, -one after the other.
Fetch html-code from web
Parse this code and save to core data storage
Use this data and batch save to calendar
Upload the parsed data to my own web server.
I have written all the code for this and it executes fine. However, at times it struggles as some of the code is executed before the other has finished.
Example:
func startProcess () {
fetchHTMLFromWeb()
parseHTML()
saveToCalendar()
//Sometimes uploadToWeb() starts before saveToCalendar() is finished
uploadToWeb()
}
I have tried reading up on GCD, but it is a rather complex subject and I am finding it hard to grasp it.
Can you recommend any good readups on this subject?
Thank you very much!
You can use the GCD to execute all your stuffs in the background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.startProcess();
});
with that, startProcess will start on the background queue/thread. So you can
In the fetchHtmlFromWeb method just call parseHtml(), when the fetch is ended.
hope it helps.
Related
I want to check if a pdf file is changed or not, and if is changed i want to update the corresponding view. I don't know if it's more suitable to use a background process as a Thread or as an NSOperation to do this task. The Apple Documentation says: "Examples of tasks that lend themselves well to NSOperation include network requests, image resizing, text processing, or any other repeatable, structured, long-running task that produces associated state or data.But simply wrapping computation into an object doesn’t do much without a little oversight".
Also, if I understood correctly from the documentation, a Thread once started can't be stopped during his execution while an NSOperation could be paused or stopped and also they could rely on dependency to wait the completion of another task.
The workflow of this task should be more or less this diagram:
Task workflow
I managed to get the handler working after the notification of type .write has been sent. If i monitor for example a *.txt file everything works as expected and i receive only one notification. But i am monitoring a pdf file which is generated from terminal by pdflatex and thus i receive with '.write' nearly 15 notification. If i change to '.attrib' i get 3 notification. I need the handler to be called only once, not 15 or 3 times. Do you have any idea how can i do it or is not possible with a Dispatch Source? Maybe there is a way to execute a dispatchWorkItem only once?
I have tried to implement it like this(This is inside a FileMonitor class):
func startMonitoring()
{
....
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: fileStringURL)
let fileDescriptor = open(fileSystemRepresentation, O_EVTONLY)
let newfileMonitorSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: fileDescriptor,
eventMask: .attrib,
queue: queue)
newfileMonitorSource.setEventHandler(handler:
{
self.queue.async
{
print(" \n received first write event, removing handler..." )
self.newfileMonitorSource.setEventHandler(handler: nil)
self.test()
}
})
self.fileMonitorSource = newfileMonitorSource
fileMonitorSource!.resume()
}
func test()
{
fileMonitorSource?.cancel()
print(" restart monitoring ")
startMonitoring()
}
I have tried to reassign the handler in test(), but it's not working(if a regenerate the pdf file, what is inside the new handler it's not executed) and to me, doing in this way, it seems a bit boilerplate code. I have also tried the following things:
suspend the DispatchSource in the setEventHandler of startMonitoring() (passing nil), but then when i am resuming it, i get the remaining .write events.
cancel the DispatchSource object and recall the startMonitoring() as you can see in the code above, but in this way i create and destroy the DispatchSource object everytime i receive an event, which i don't like because the cancel() function shoul be called in my case only when the user decide to disable this feauture i am implementing.
I will try to write better how the workflow of the app should be so you can have an more clear idea of what i am doing:
When the app starts, a functions sets the default value of some checkboxes of the window preference. The user can modify this checkboxes. So when the user open a pdf file, the idea is to launch in a background thread the following task:
I create a new queue call it A and launch asynch an infinite while where i check the value of the UserDefault checkboxe (that i use to reload and update the pdf file) and two things could happen
if the user set the value to off and the pdf document has been loaded there could be two situations:
if there is no current monitoring of the file (when the app starts): continue to check the checkboxe value
if there is currently a monitoring of the file: stop it
if the user set value to on and the pdf document has been loaded in this background thread (the same queue A) i will create a class Monitor (that could be a subclass of NSThread or a class that uses DispatchSourceFileSystemObject like above), then i will call startMonitoring() that will check the date or .write events and when there is a change it will call the handler. Basically this handler should recall the main thread (the main queue) and check if the file can be loaded or is corrupted and if so update the view.
Note: The infinite while loop(that should be running in the background), that check the UserDefault related to the feature i am implementing it's launched when the user open the pdf file.
Because of the problem above (multiple handlers calls), i should use the cancel() function when the user set checkboxe to off, and not create/destroy the DispatchSource object everytime i receive a .write event.
I am writing a small CEP program using Siddhi. I can add a callback whenever a given filter outputs a data like this
executionPlanRuntime.addCallback("query1", new QueryCallback() {
#Override
public void receive(long timeStamp, Event[] inEvents, Event[] removeEvents) {
EventPrinter.print(inEvents);
System.out.println("data received after processing");
}
});
but is there is a way to know that the filter has finished processing and it won't give any more of the above callback. Something like didFinish. I think that would be the ideal place for shutting down SiddhiManager and ExecutionPlanRuntime instances.
No. There in no such functionality and can't be supported in the future also. Rationale behind that is, in real time stream processing queries will process the incoming stream and emit an output stream. There is no concept as 'finished processing'. Query will rather process event as long as there is input.
Since your requirement is to shutdown SiddhiManager and ExecutionPlanRuntime, recommended way is to do this inside some cleaning method of your program. Or else you can write some java code inside callback to count responses or time wait and call shutdown. Hope this helps!!
How can I suspend a Task from Rest API.
I'm using the following code
RuntimeEngine engine = sessionBean.getEngine(implementationId);
TaskService taskService = engine.getTaskService();
taskService.start(taskId, actorId);
taskService.complete(taskId, actorId, data);
It works fine, now I want to save task Status between start and complete in different moments, but I don't know How to pass the data Map in order to hold the actual State.
taskService.suspend(taskId, actorId);
You can take a look at the implementation of the Save operation in the jbpm console.
That's done via saving the output values of the task as far as remember. By the way, suspend is not the right method to call to save the state, because it means a completely different thing.
You can start looking at here: https://github.com/droolsjbpm/jbpm-console-ng/blob/master/jbpm-console-ng-human-tasks-forms/jbpm-console-ng-human-tasks-forms-client/src/main/java/org/jbpm/console/ng/ht/forms/client/editors/taskform/FormDisplayPresenter.java
and go down to the actual implementation.
Regards
I am trying to download files from remote, and I now can monitor every single files download success status
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
But any way to monitor the whole process of downloading? How should I know all downloads are finished?
And I tried start download request with
[afhttpClient enqueueBatchOfHTTPRequestOperations:operationArray
progressBlock:progressBlock
completionBlock:completionBlock];
seems not work, so what the difference between above code and start download request with [operation start] in a loop?
#mattt (if you can see this)
You most probably have an NSArray of URL objects that you use to download images. What you need to do is to create an integer value equal to the count of your URL objects. Each time you successfully download an image or absolutely fail to download it (for instance after few timeouts or upon receiving 404 HTTP status code) you need to decrement that integer (note that it should be an atomic property, since blocks are being executed on different threads). Once the count reaches zero - all requests are finished. You can also use that integer to update a progress bar or simply notify user that "#/15 images are downloaded". Let me know if you need any other clarifications.
And unfortunately I have not worked with AFHTTPClient, so I can't tell you the difference between the two operations precisely, but contextually, first one executes all the requests almost at the same time asynchronously and the latter one uses consecutive approach, where second request will only be launched upon completion of the first one.
You can create NSOperationQueue and put all AFHTTPRequestOperation into it.
To observe the "operations" by using KVO. When the count go to zero, that is the time to say all operations completed.
If what you want is a constant progress update for each operation with bytes downloaded and total expected then I can highly recommend Peter Steinberger's AFDownloadRequestOperation.
This class derives from AFHTTPRequestOperation and adds a progressiveDownloadProgressBlock per-operation rather than just a per-operation-completion progress at the operation queue level, which is what I think you're looking for. Another great bonus is that it makes resumable/partial downloads much more accessible than in the core AFNetworking implementation.
it's this easy to use (example from the GitHub project's README.md):
[pdfRequest setProgressiveDownloadProgressBlock:^(NSInteger bytesRead,
long long totalBytesRead, long long totalBytesExpected,
long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile)
{
self.downloadProgress = totalBytesReadForFile/(float)totalBytesExpectedToReadForFile;
}];
I use this in a few enterprise iOS projects to download multi-gigabyte files and I can tell you that it works great with the 1.0.1 release of AFNetworking.
Hope that helps…
i have made one list of images + respective data in tableview.
it takes long time while loading
i want to make multithreading two methods
1> parsing of data
2> parsing of images
i want to execute parsing of data first after that i can select any of rows listed even though images not been loaded(/parsed) because the images is parsed after the parsing of data and it takes long time.
from where should i call these both the methods.
and how enable the selection on row after parsing of the data...
how to do multithread both the methods
waiting for your great responce
Thanking in advance
You likely don't want to use NSThreads - at least not directly.
What you do is subclass NSOperation.
There are a few ways to do what you have in mind. If you know the total number of rows in your table right from the start, then things are simpler:
Make a subclass of NSOperation called MyParseDataOperation. Then make one MyParseDataOperation for each row in your table. When the operation is done, you need to message your main thread with the resulting data.
Code below is full of errors, incomplete. etc.
ie in your MyParseDataOperation class:
MyParseDataOperation
-(id)initWithStuff:(NSURL*)stuff forTableRow:(int)row;
{
blah blah -
// here is where I make sure I have all the data I need for main() which is called in the background on some random thread at some future time.
}
-(void)main;
{
// use data like Urls, file names, etc passed in to the initWithStuff method
get stuff
parse stuff
// ok now you have the data
NSMutableDictionary* parsedData = [NSMutableDictionary dictionary];
[parsedData setObject:[NSNumber numberWithInt:row] forKey:#"row"];
[parsedData setObject:stuff i figured out forKey:#parsed];
[tableDataSource performSelectorOnMainThread:#selector(dataParsed) withObject:parsedData];
}