Multiple AFHTTPRequestOperations that has dependency of each other - concurrency

What I trying to achieve is send two request to the server which orders are matter,and the second request's parameters is unknown until the first request result comes back.
I already tring as the following code snippet using the afnetworking2.0
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
NSMutableURLRequest*request=[NSMutableURLRequest requestWuthURL#"URLSTRING"];
// configure the request with parameters
[request setHTTPBody:JsonData];
[request setHTTPMethod:#"POST"];
AFHTTPRequestOperation* operation=[[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setComplemetionBlockWithSucess:^(AFHTTPRequestOperation* operation, id responsObject)
{
//parse the result using NSXMLParser;
NSInteger result=weakSelf.parseRule.identifier;
}
failure :^(AFHTTPRequestOperation* operation, NSError *error)
{
NSLog(#"fail");
}];
NSMutableURLRequest*secondRequest=[NSMutableURLRequest requestWuthURL#"URLSTRING"];
//Using the first request result to set the parameters in second request
[secondRequest setHTTPBody:JsonData];
[secondRequest setHTTPMethod:#"POST"];
AFHTTPRequestOperation* secondOperation=[[AFHTTPRequestOperation alloc]initWithRequest:secondRequest];
[secondOperation setComplemetionBlockWithSucess:^(AFHTTPRequestOperation* operation, id responsObject)
{
//do something
}
failure :^(AFHTTPRequestOperation* operation, NSError *error)
{
NSLog(#"fail");
}];
[secondOperation addDependency:Operation];
[queue addOPerations:#[operation,secondOperation]];
Which didn't work, I can get back the first operation result correctly,but the thing is that my second request params setting is execute before the result comes back.Any advice will be really appreciated.
Should I use the dispatch_semaphore? Or Any other suggestion?

Related

does NSMetadataQueryDidUpdateNotification can work with NSFileManager setUbiquitous

i am trying to track my icloud upload progress using NSMetadataQueryDidUpdateNotification..but it can't work... i don't know what the problem is..
here is my code for upload to icloud
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:backupUrl options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *newURL) {
NSFileManager* fm = [NSFileManager defaultManager];
NSError *theError = nil;
BOOL success =[fm setUbiquitous:YES itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:#"Documents" isDirectory:true] URLByAppendingPathComponent:bName] error:&theError];
if (!(success)) {
[progView dismiss];
UIAlertView* alertFail=[[UIAlertView alloc]initWithTitle:#"Backup Error" message:#"Could not backup to iCloud." delegate:Nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertFail show];
NSLog(#"iCloud error: %#", [theError localizedDescription]);
}
else{
[self loadNotes:bName];
}
}];
});
and this code for tracing my upload progress
- (void)loadNotes:(NSString *)bname {
self.alertQuery = [[NSMetadataQuery alloc] init];
[self.alertQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, bname]];
[self.alertQuery setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(liveupdate:) name:NSMetadataQueryDidUpdateNotification object:self.alertQuery];
[self.alertQuery startQuery];
}
-(void)liveupdate:(NSNotification *)note {
NSMetadataQuery* query=[note object];
if ([query resultCount]==0){
return;
}
NSMetadataItem* item=[query resultAtIndex:0];
float progress=[[item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey]floatValue];
[progView.progBar setProgress:progress animated:NO];
if ([[item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey] boolValue]){
[query stopQuery];
[query disableUpdates];
_alertQuery=nil;
[progView dismiss];
}
}
what is the wrong with code...
can somebody tell me what is the best way to track icloud upload progress in NSFileManager setUbiquitous....
thank you...
You will probably want to observe the NSMetadataQueryDidFinishGatheringNotification notification, which fires first, with the initial set of results.
But even then, you may not get what you want, because the update notification will only fire if the set of results changes. You are searching for a particular file, and since that file is not being deleted or anything like that, your set of results will remain the same, even if the file uploads or downloads.
In my experience, NSMetadataQuery is not very effective for monitoring upload and download progress. You can hack it to almost work, but it is never exactly what you want.
Probably the best you can do is fire the metadata query, observe the finished-gathering notification, stop the query, and start the query again. Do this at regular intervals of a second or so, and you should be able to track the progress.
You should also consider whether you really want to track progress of an individual file. It will depend how large your files are. In many cases, you may be better to track the number of files to upload/download, or the total bytes remaining.
If this is the case, you can try to setup a metadata that includes a predicate with the uploaded/downloaded status included. This will continually fire notifications when a file finishes uploading/downloading. You can find an example of this here. Look for the method startMonitoringMetadata.

percent escapes removed in NSData writeToURL

I am trying to cache an image retrieved from Flickr. In order to create a unique filename for the cached image, I use CFURLCreateStringByAddingPercentEscapes to percent escape the URL. Appending that to the cache directory, I get a URL with the embedded Flickr URL properly percent escaped; but when I try to cache the image using NSData writeToURL:options:error: I get "The operation couldn’t be completed. No such file or directory" - and it shows the file URL with the original, unescaped Flickr URL where the file name should be.
For example, I NSLog the URL as:
file://localhost/Users/rick/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/77C4A7AA-C386-4575-AD21-B4027D080408/Library/Caches/http%3A%2F%2Ffarm3.static.flickr.com%2F2887%2F9391679341_26643bcafa_b.jpg
but the error message shows
NSFilePath=/Users/rick/Library/Application Support/iPhone Simulator/6.1/Applications/77C4A7AA-C386-4575-AD21-B4027D080408/Library/Caches/http://farm3.static.flickr.com/2887/9391679341_26643bcafa_b.jpg
It's as if in the process of converting the URL to a file path, writeToURL is removing the percent escapes.
Is there a way to prevent this from happening, or do I just need to come up with another way to generate unique names based on the url?
Here's the relevant code:
NSURL *cacheDirectoryURL=[[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString *photoURLString= (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef)([self.photoURL absoluteString]),
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8));
if (photoURLString)
{
NSURL *cachedPhotoURL=[NSURL URLWithString:[[cacheDirectoryURL absoluteString] stringByAppendingString:photoURLString]];
NSData *photoData=[NSData dataWithContentsOfURL:cachedPhotoURL];
if (photoData)
{
UIImage *image=[UIImage imageWithData:photoData];
self.imageView.image=image;
[self setupScrollView]; // new image, need to adjust scroll view
} else {
dispatch_queue_t fetchQueue=dispatch_queue_create("photo downloader", NULL);
dispatch_async(fetchQueue, ^{
NSData *photoData=[NSData dataWithContentsOfURL:self.photoURL];
NSError *error;
if ([photoData writeToURL:cachedPhotoURL options:NSDataWritingAtomic error:&error])
{
NSLog(#"Cached photo");
} else {
NSLog(#"Failed to cache photo");
NSLog(#"%#",error);
}
});
}
}
Thanks in advance for your help!
The problem is that [NSURL URLWithString:...] parses the given string and interprets the
percent escapes. Generally, to create a URL for a file system path, fileURLWithPath:
should be used.
In your case, the following simple code should work:
NSURL *cachedPhotoURL = [cacheDirectoryURL URLByAppendingPathComponent:photoURLString]

How can I count the amount of Facebook friends in iOS sdk?

I'm trying to figure out how to get a random userID from my friends.
is there a way to do it with "friendPickerController" ?
the only "count" method I've found is in the selection, which dosen't help.
You can get the total friend count using following method
FBRequest* friendsRequest = [FBRequest requestForMyFriends];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error) {
NSArray* friends = [result objectForKey:#"data"];
NSLOG(#"Total Friend :%#",friends.count);
}];
Just updating in case this helps anyone. While Dipak's answer worked flawlessly for me at the end, it didn't work until I added permission to retrieve the count. I added the following lines of code just before Dipak's code and it returned me the proper friend count.
NSArray *permissions = [NSArray arrayWithObjects:#"friends_about_me", nil];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
}];
[FBSession setActiveSession:[FBSession activeSession]];

How can I get optimistic concurrency with JPA annotation

I am using JPA 3, with annotation (no mapping file) and with provider org.hibernate.ejb.HibernatePersistence
I need to have optimistic concurrency.
1)I tried to rely on the tag called , it did not work.
2)
So I decided to do it with java code. I have a mergeServiceRequest method and an object with type Request as follows: I start a transaction, lock the request object,
then try to get a Request object newRequest from database, compare its timestamp with the current one request. If they do not match, I throw an exception; if they match, then I update the current request enter code herewith current time and save it to database.
I need to lock the object manually, because by starting a transaction from session, it does not put a lock on the row in database. I wrote some java code which shows that a transaction does not lock the record in database automatically.
Problem with this approach is the query
Request newRequest=entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
always return same object as request. "request" is in the session entityManger, and the query always return what is cached in the session. I tried all the five query.setHint lines and I still get same result: no database query is performed, the result is from session cache directly.
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Query query = entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
//query.setHint("javax.persistence.cache.retrieveMode", "BYPASS");
//query.setHint("org.hibernate.cacheMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.cache.retrieveMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.retrieveMode", CacheMode.REFRESH);
//query.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
Request newRequest=(Request)query.getSingleResult();
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
}
3)So I also tried to use another session get query the newRequest, if I do that, the newRequest will be different from request. But for some reason, if I do that, then the lock on request object is never released, even after the transaction commit. Code looks like below
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Request newRequest=findRequest(request.getServiceRequestId()); // get it from another session
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
//lock on the database record is not released after this, and even after entityManager is closed
}
Could anyone help me on this?
Thanks.
Daniel

Passing parameter in Restful webservices

Dear Stackoverflow users,
I have been playing around with restful webservice for quite a while now.
I have a small doubt in how to pass a parameter using GET method.
As get can only be used to retrieve any resources, how is it possible to pass parameter.
I have written a small code for this, but there seem to be something wrong with the code.
#GET
#Produces("text/plain")
#Path("/instrumentname/")
public String getname(String name1) {
try {
String [] env=null;
String[]callAndArgs= {"python","connection.py",ins_name};//passing the parameters
Process p = Runtime.getRuntime().exec(callAndArgs,env,
new java.io.File("C:\\Users\\Balkishore\\Documents\\NetBeansProjects\\Testinstrument_Rest\\build\\web"));//excuting the python file
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));//getting the input
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));//getting the error
interface_name = stdInput.readLine();//reading the output
System.out.println(interface_name);
}
catch (IOException e) {//catching the exception
System.out.println("exception occured");
e.printStackTrace();
System.exit(-1);
}
return this.interface_name;
}
Any help would be very much appreciated.
Thanks a ton in advance.
Cheers!
you just need to concatenate parameters at the end of the URL in following format:
www.xyz.com/?param1=val1&param2=val2&param3=val3
where param1, param2 are parameter names and val1,val2 are values for the corresponding parameters... You can just type them in a browser's URL bar instead of writing an HTML page or a script for testing...
Also, you are right in saying that GET is Generally used to fetch resources from a web server, but at times you have to pass information whose resource has to be fetched...