Guarantee Order in NSURLConnection - objective-c

Let me start off with some code. When the application loads, it calls the following:
//Creates custom URL for request, loads the request, and upon completion (as per the delegate response, it runs the selector)
//List of programs
URLCreator * getListURL = [[URLCreator alloc] initStandard:#"getList"];
WebManager *getListWM = [[WebManager alloc]init];
[getListWM load:[getListURL finalURL] withSelector:#selector(createProgramList)];
//Sorting order for program list
URLCreator * getSortURL = [[URLCreator alloc] initStandard:#"getSort"];
WebManager *getSortWM = [[WebManager alloc]init];
[getSortWM load:[getSortURL finalURL] withSelector:#selector(sortThroughPrograms)];
This code so far works well except for one thing - my responses come out of order. This is to be expected because the list of programs is much larger than the sorting order. Basically, what needs to happen is I need to guarantee I have the list of programs AND the sorting order before I can perform any type of sorting algorithm.
Without locking up the program by doing a synchronous request, what is the best way to guarantee that I have BOTH before performing the sorting algorithm? Sure, I can set BOOL flags, but I would need to constantly check to see when both have been received.

You could use NSOperationQueue for this.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html

Related

Best way to do a massive data sync from HealthKit?

I am looking for a smart way to import ALL data for ALL time from HealthKit in a smart way for high volume users who log certain HealthKit values hundreds of times a day for months or years. I'm also looking to do this off the main thread and in a way that is robust to the fact that users can close the app whenever they feel like. Here's what my current implementation is:
- (void) fullHealthKitSyncFromEarliestDate {
dispatch_queue_t serialQueue = dispatch_queue_create("com.blah.queue", DISPATCH_QUEUE_SERIAL);
NSLog(#"fullHealthKitSyncFromEarliestDate");
NSDate *latestDate = [PFUser currentUser][#"earliestHKDate"];
if (!latestDate) latestDate = [NSDate date];
NSDate *earliestDate = [healthStore earliestPermittedSampleDate];
NSLog(#"earliest date %# and latest date %#", earliestDate, latestDate);
if ([earliestDate earlierDate:[[NSDate date] dateByAddingYears:-2]] == earliestDate) {
earliestDate = [[NSDate date] dateByAddingYears:-1];
}
__block NSDate *laterDate = latestDate;
__block NSDate *earlierDate = [latestDate dateByAddingMonths:-1];
int i = 0;
while ([earlierDate earlierDate:earliestDate] == earliestDate) {
// DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(i * 30 * NSEC_PER_SEC)), serialQueue, ^{
NSLog(#"calling sync from %# to %#", earlierDate, laterDate);
[self syncfromDate: earlierDate toDate:laterDate];
laterDate = [laterDate dateByAddingMonths:-1];
earlierDate = [laterDate dateByAddingMonths:-1];
earlierDate = [[earliestDate dateByAddingSeconds:1] laterDate:earlierDate];
});
}
}
I am having a few problems with the above code:
earlierDate is sometimes not getting updated for the next iteration. It's like there's some weird overlap that sometimes the same date range gets called twice or even more times.
Kernel memory allocation issues (as I retrieve objects I queue them for upload to a remote server)
Interface stops responding entirely even though this is all happening off the main queue. There may be something way down stream that gets called at the end of the entire query...but I'm still surprised the interface basically stops responding altogether. It usually does fine with similar syncing for short time periods. And here I'm just doing a month at a time in queries spaced 30 seconds apart
I realize without the details of additional code this may be too murky to address, but can people tell me what sort of solutions you have implemented for cases where you want to retrieve massive amounts of data from HealthKit. I realize I may get responses like 'that's what HealthKit is for...why are you duplicating all that data?'. Suffice it to say it's required and there's no way around it.
Also, am I just misunderstanding entirely how to use a serial queue?
Ideally I'd like to do the following: (1) Run only one query at a time in this for loop (2) and run them with some reasonable period of time between them, say 30 seconds apart, because at the end of each query I do need to do some interface updates on the main qeue (3) do all the queries on a background loop in such a way that it's not degrading interface performance and can be killed at any time the user decides he's gonna kill the app. That's what I thought I would achieve with the above...if folks can tell me where my threading is going wrong I'd really appreciate it. Thanks!

Return value from asynchronous SQL method

I have this code:
- (NSString *)obtenerDatosUsuario
{
__block NSString *result=#"";
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
result=resultadoSQL;
}];
return result;
}
And I want that the return be the content of resultadoSQL
If my guess is correct about what happens inside your method -obtenerDatosUsuarioSQL: (i.e., it performs a lengthy operation in a background thread, and gives the result to the passed block argument), then your code runs in the following order:
You call -obtenerDatosUsuario
You call -obtenerDatosUsuarioSQL:, passing a completion handler block.
Execution proceeds forward and reaches the return statement at the end of -obtenerDatosUsuario, and exits the method body. The returned variable result hasn't been set yet!
Sometime later, the SQL query completes and the block is executed. But it is too late to return the result because execution already exited the method -obtenerDatosUsuario.
There are ways to make this asynchronous method behave synchronously (e.g. semaphores), but it generally is a very, very bad idea. Most likely, obtenerDatosUsuarioSQL is asynchronous because there is a chance (even if only a small chance) that the result won't be returned immediately. Maybe it's possible that the SQL will be slow. Or maybe you'll eventually be doing queries from multiple threads, so this query might have to wait for queries in other threads to finish. Or there might be other reasons. But whatever the reason, this method was implemented as asynchronous method, and you should embrace that, rather than fight it. If you change obtenerDatosUsuario to return synchronously, you open yourself to a wide variety of possible problems.
Instead, you should just adopt asynchronous pattern in your code. For example, let's imagine that you have some code that was planning on using the result of obtenerDatosUsuario for some other purpose, e.g.:
NSString *resultadoSQL = [self obtenerDatosUsuario];
// use `resultadoSQL` here
Just change that to:
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
// use `resultadoSQL` here
}];
// but not here
And, if you're using obtenerDatosUsuarioSQL in some method that you're currently trying to return the value immediately, then change that to behave asynchronously, too. For example, let's assume you had something like:
- (NSString *)someOtherMethod {
NSString *resultadoSQL = [self obtenerDatosUsuario];
// let's assume you're doing something else with `resultadoSQL` to build some other string
NSString *string = ... // some expression using `resultadoSQL`
return string;
}
Then, you'd change that to also adopt asynchronous pattern:
- (void)someOtherMethod:(void (^)(NSString *))completionHandler {
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
NSString *string = ... // some expression using `resultadoSQL`
completionHandler(resultadoSQL);
}];
}
When you first encounter this, this may seem unnecessarily complicated, but asynchronous programming is so critical, such a fundamental part of Cocoa programming, that one really must gain some familiarity with these common asynchronous patterns, such as blocks. Personally, we use block syntax so much that I create code snippets in Xcode's "Code Snippet Library" for typical block patterns, which simplifies life a lot and gets you out of the world of memorizing the unintuitive block syntax.
But don't be tempted to wrap asynchronous method in another method that makes it behave synchronously. You open yourself up to many types of problems if you do that.

problem with saving data at coredata?

In my application there is searchBar. when we input a text, it will do functionGrab (grab data from internet and save it to coredata), example :
if we input "Hallo"
if([[dict objectForKey:#"Category"] isNotEmpty] && [[[dict objectForKey:#"Category"] objectAtIndex:0] class]!=[NSNull class]){
NSMutableArray * DownloadedTags =[dict objectForKey:#"Category"];
NSMutableSet * TagsReturn=[NSMutableSet set];
for(int i=0;i<[DownloadedTags count];i++){
NSString * Value=[DownloadedTags objectAtIndex:i];
Tag * thisTag= (Tag*)[GrabClass getObjectWithStringOfValue:Value fromTable:#"Tag" withAttribut:#"Name"];
[TagsReturn addObject:thisTag];
}
NSMutableSet * manyManagedObjects = [BusinessToSave mutableSetValueForKey:#"Tags"];
[self removeDifferenceBetween2MutableManagedObjectSets:manyManagedObjects withDownloadedVersion:TagsReturn];
}
So each biz has many categories. WHat happen in multi threaded application is one thread put category. The other thread also put the same category before committing.
So, [GrabClass getObjectWithStringOfValue:Value fromTable:#"Tag" withAttribut:#"Name"]; gives a new object even though some other thread already created the same object without knowing it.
If I synchronized the whole thing that the code would run serially and that'll be slow.
functionGrab:"H"
functionGrab:"Ha"
functionGrab:"Hal"
functionGrab:"Hall"
functionGrab:"Hallo"
something like,it do that functionGrab 5 times
I want to make functionGrab at background, but the problem is when I do that function without synchronized it will save more than one of data, so the result is there are 5 hallo words in my coredata, but if I do that with synchronized, it spent so much time, so slow..
is there any way to help my problem?
I do not recommended having more than one thread "creating" the same types of data for the exact reason you are running into.
I would suggest you queue all of your "creates" into a single thread and a single NSManagedObjectContext to avoid merge or duplication issues.
The other option would be to make the app Lion only and use the parent/child NSManagedObjectContext design and then your children will be more "aware" of each other.

How to get hold of the currently executing NSOperation?

Is there an equivalent to [NSOperationQueue currentQueue] or [NSThread currentThread] for NSOperation?
I have a fairly complex domain model where the heavy processing happens quite deep down in the call stack. In order to timely cancel an operation I would need to pass the NSOperation as a parameter to every method until I get to the point where I want to interrupt a longer running loop. Using threads I could use [[NSThread currentThread] isCancelled] so it would seem convenient if there is an equivalent for NSOperation, unfortunately there is only the seemingly useless [NSOperationQueue currentQueue].
Came up with an extension in swift that returns the running operations
extension NSOperationQueue {
public var runningOperations: [NSOperation] {
return operations.filter {$0.executing && !$0.finished && !$0.cancelled}
}
}
You can then pick up the first one
if let operation = aQueue.runningOperations.first {}
No, there's no method to find the currently executing operation.
Two ways to solve your problem:
Operations are objects. If you need object A to talk to object B, you'll need to arrange for A to have a reference to B. There are lots of ways to do that. One way is to pass the operation along to each object that needs to know about it. Another is to use delegation. A third is to make the operation part of some larger "context" that's passed along to each method or function. If you find that you need to pass a reference from one object through several others just to get it to the object that will finally use it, that's a clue that you should think about rearranging your code.
Have the "heavy lifting" method return some value that gets passed up the call chain. You don't necessarily need the heavy lifting method to call [currentOperation cancel] to accomplish your goal. In fact, it would be better to have it return some value that the operation will understand to mean "work is done, stop now" because it can check that return value and exit immediately rather than having to call -isCancelled once in a while to find out whether it has been cancelled.
This isn't a good idea. Operations are usually canceled by their queue. Within the operation's main() method, you can periodically check if self is cancelled (say, every n trips through a loop, or at the start of every major block of commands) and abort if so.
To respond to a cancellation (say, some UI element tied to the operation's or queue's status), you use key value observing (KVO) to have your controller observe the operations' started, completion, and cancelled properties (as needed), then set your UI's state (always on the main thread) when those keys are updated. Per JeremyP's comments, it's important to note the KVO notifications come from the op's thread and UI should (almost) always be manipulated on the main thread, so you'll need to use -performSelectorOnMainThread... methods to update your actual UI when you receive a state change KVO note about your operations.
What are you really trying to do? That is, why do you feel other parts of your app need to know directly about the current operation?
You could store the current operation in the thread dictionary. Just remember to get rid of it before you exit. You can safely use the thread dict if you created the object.
You can use a combination of [NSOperationQueue currentQueue] & [NSThread currentThread] to accomplish this.
Essentially, you need to loop through the operations on the currentQueue and find the operation running on the currentThread.
NSOperation doesn't provide access to the thread it is running on, so you need to add that property yourself and assign it.
You're probably already subclassing NSOperation and providing a main, so add a 'thread' property to that subclass:
#interface MyOperation : NSOperation
#property(nonatomic,strong) NSThread *thread ;
#end
Then, in your 'main' assign the current thread to that property
myOperation.thread = [NSThread currentThread]
You can then add a 'currentOperation' method:
+(MyOperation *)currentOperation
{
NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ;
NSThread *currentThread = [NSThread currentThread] ;
for( MyOperation *op in opQueue.operations ) {
if( [op isExecuting] && [op respondsToSelector:#selector(thread)] ) {
if( op.thread == currentThread ) {
return ( op ) ;
}
}
}
}
return nil ;
}
How do you know which operation you want to cancel?
When you get to the point that you want to cancel, just call [myQueue operations] and go through the operations until you find ones that you now want to cancel. I guess if you have millions of operations (or thousands) this might not work.
[myQueue operations] is thread safe - a snapshot of the Queue contents. You can dive through it pretty quick cancelling at will.
Another way:
NSOperationQueue is not a singleton, so you can create a Q that has say 200 jobs on it, and then cancel all 20 by just getting that Q and cancelling them all. Store the Q's in a dictionary on the main thread, and then you can get the jobs you want canceled from the dict and cancel them all. i.e. you have 1000 kinds of operations and at the point in the code where you realize you don't need a certain task, you just get the Q for that kind, and look through it for jobs to cancel.

Turn id back into a reference object in AppScript objective-c

I'm writing an app that talks to Mail using Objective-C-appscript (objc-appscript). I want to make a copy of the currently selected mail messages and perform some processing on it at a later -- at which time the current selection may have changed.
MLApplication *mail = [[MLApplication alloc] initWithBundleID: #"com.apple.mail"];
MLReference *ref = [mail selection];
id theSelection = [[ref getItem] copy];
// Do something here, which may change the contents of ref,
// but that's okay since I made a copy in theSelection
MLMoveCommand *cmd = [[theSelection move] to: [[mail mailboxes] byName:#"test"]];
// This command should move the selected messages to the mailbox but fails
// because theSelection
MLReference *ref2 = nil; // Need to turn theSelection into an MLReference *
MLMoveCommand *cmd = [[ref2 move] to: [[mail mailboxes] byName:#"test"]];
I need to turn theSelection back into an MLReference *. I'm sure this should be a simple operation, but I am new to appscript and require some guidance. Thanks!
You can always cast theSelection to whatever type you want it to be. You can also query it and find out what type it thinks it is using the class method. You probably don't have to do this though.
For example,
NSString *something = [(MLReference *)theSelection someFuncIMadeUp];
You can read all about the runtime stuff (like the class method) in the apple doc:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
You're assuming Apple event IPC uses proxy objects like Distributed Objects, but that's not the case: it's RPC + queries. (Think XPath over XML-RPC as a rough analogy.) It's a common misconception - Apple themselves totally fail at explaining it - but grasping Apple events' query-based nature is essential to controlling scriptable apps effectively.
Anyway, here's where you're going wrong:
id theSelection = [[ref getItem] copy];
This line copies an MLReference object identifying Mail's selection property, but as a reference is basically analogous to a URL that's effectively a no-op.
MLMoveCommand *cmd = [[theSelection move] to: [[mail mailboxes] byName:#"test"]];
This line tells Mail to move the object(s) it finds at the referenced location. That command may or may not work depending on how capable Mail's scripting support is (some apps may be capable of manipulating multiple objects with a single command; others are limited to a single object per command). But even if it does work, it will be operating on whatever's selected at the time the command is sent - which isn't what you're after.
The correct solution in this case is to use a get command to retrieve a list of references (in this case, an NSArray of MLReference instances), which you can later iterate over to move each of the referenced messages in turn. Fortunately, the references that Mail returns identify messages by id, which means that they should continue pointing to the original message objects even if they're moved in the meantime. (By-index and by-name references are much less stable, so you need to be a lot more careful working with apps that use those.)
For example (error checking omitted for clarity):
MLApplication *mail = [MLApplication applicationWithBundleID: #"com.apple.mail"];
NSArray *messageRefs = [[mail selection] getItem];
// do other stuff here
MLReference *message;
for (message in messageRefs) {
MLMoveCommand *cmd = [[mail move: message] to: [[mail mailboxes] byName: #"test"]];
id result = [cmd send];
}
See the appscript manual for more information. Also, ASTranslate is your friend.