Situation.
XMLProxy Class is singleton. XMLRequest Class too.
Normally, when I want to request URL.
Example :
XMLProxy *xmlProxy = [XMLProxy sharedInstance];
[xmlProxy tryGetDataWithParameter:example_parameter];
// Method "tryGetDataWithParameter" will call method "requestURL" from XMLRequest Class
// Assume that is [xmlRequest requestURL];
// and XMLProxy Class (XMLProxy delegate) will create xml parser for each "example_parameter"
type to response xml data receive.
It's no problem.
Question?
I want to create visual background process to request URL and I create AutoSending Class that is singleton.
I want to use AutoSending Class to call method
"tryGetDataWithParameter" (from XMLProxy class). Example to call :
[autoSending start];
-(void)start{ XMLProxy *xmlProxy = [XMLProxy sharedInstance]; [xmlProxy tryetDataWithParameter:example_parameter]; }
Can I use NSThread to call statement "[autoSending start]";
It is the result of a visual Background Process.
Rather than try to code all this up by yourself, why not use a library like AFNetworking which is built on top of NSURLConnection, NSOperation, and other standard IOS technologies. You can then use NSOperationQueue to run your request on another thread.
Related
I'm attempting to use an Objective C wrapper for a Flickr API (ObjectiveFlickr). The wrapper works with an Objective-C code example. I'm trying to use it with Swift and as soon as the wrapper tries to find the first delegate method, it fails on this assertion.
NSAssert([delegate respondsToSelector:#selector(flickrAPIRequest:didObtainOAuthRequestToken:secret:)],
#"Delegate must implement the method -flickrAPIRequest:didObtainOAuthRequestToken:secret: to handle OAuth request token callback");
[delegate flickrAPIRequest:self didObtainOAuthRequestToken:oat secret:oats];
Here's the delegate method signature.
class FlickrDelegate : NSObject, OFFlickrAPIRequestDelegate
{
func flickrAPIRequest(inRequest:OFFlickrAPIRequest,
didObtainOAuthRequestToken inToken:String,
secret inSecret:String) {
...
}
}
I'm a complete novice with what I'm trying to do, so perhaps I've made some terribly dumb mistake.
Did you set your delegate property on flickrAPIRequest class in viewdidload to receive messages from Flikr?
I have a DataManager class that is responsible for fetching data and handing it over to the DatabaseManager, which in-turn will insert it into core data.
The method that exposes itself to the webservice is below
-(void)fetchDetailsForId:(NSString *)userId withFieldInformation:(NSString *)fieldInfo
{
if (SessionIsActive) {
[APIRequester startWithRequest:[NSString stringWithFormat:#"%#?%#",userId, fieldInfo]
completionHandler:^(APIConnectionManager *connection, id user, NSError *error) {
//This is where the results are returned and the API manages its own threads and returns the result lazily
}];
}
}
The above method is within the DataManager class. Now, a few methods in the same class call the above method to get data from the server. This fetched data is then forwarded to the DatabaseManager for inserting into core data. A sample of this is
-(void)fetchCurrentDataForLoggedInUser
{
NSData *fetchedData = [self fetchDetailsForId:loggedInId withFieldInformation:#"all"];
//the fetchedData is then forwarded to DatabaseManager
}
Now, since the web method (first method) gets the data in the background thread (managed by the API), the value of the "fetchedData" in the above method will be null since the web method exits before the API gets the relevant data.
Can someone tell me the most recommended way of handling a situation like this? I am not asking for sample code or anything, just the right direction should be enough. I am looking for a permanent solution than a hack or easy workaround.
Thank you
Make a property for NSData says fetchedData. in .h and synthesize it in .m
then set this property after date fetch then call the method which is required. There are some delegate which tells you data data loading is done so at there you can set your property an from background you can call UI updating method on main thread that gives you your desired result.
you can use selector like this for calling on main thread
[self performSelectorOnMainThread:#selector(rollBar:)
withObject:nil
waitUntilDone:false];
I have a class, which has a delegate based system for sending different type of requests. it uses delegate to tell the object when the request is complete and also if it was a success o an error.
Now, I also have to check what type of request was it in response to take appropriate action.
I have wrapper class that should give me a block based interface for the same.
I pass a completion-block and an error-block to a request method which should internally use this delegate based class.
And when the response comes, should automatically call the appropriate handler for that request type and depending on success and error as well.
I saw a similar question on SO, but it was a little unclear to me, So please give a general idea of how to go about it instead of marking it as duplicate straight away.
Here is one way to do it. Use this RAExpendable class to dynamically build a delegate with a block based implementation.
Let's say your delegate is:
#protocol XDelegate
-(void) foo:(id)response;
#end
Add RAExpendable.h, RAExpendable.m from https://github.com/evadne/RAExpendable to your project. Dynamically add the delegate method:
RAExpendable *expendable = [RAExpendable new];
[expendable addMethodForSelector:#selector(foo:) types:"v#:#" block:^(id x, SEL sel, id response){
NSLog(#"response is %#", response);
}];
And set the expendable class as your delegate:
someObject.delegate = expendable;
Now, if you do this:
[expendable performSelector:#selector(foo:) withObject:#"OK"];
You get the string response is OK. Replace NSLog with whatever success/failure implementation you see fit. From now on, when you call foo:, the block executes instead.
If you want to modify this for your use case, note that the parameters for this example were v#:#, which according to the Type Encoding guide of the runtime means: void return, self, SEL, object. self and SEL are the two hidden parameters present on every Objective-C methods, the third parameter is the first non hidden parameter of the method. The signature of the block has to match the signature of the method.
With REKit, you can make a delegate dynamically like below:
id dynamicDelegate;
dynamicDelegate = [[NSObject alloc] init];
[dynamicDelegate respondsToSelector:#selector(foo:) withKey:nil usingBlock:^(id receiver, id response) {
NSLog(#"response is %#", response);
}];
someObject.delegate = dynamicDelegate;
In order to use asynchronous http requests in objective c, you need to set a delegate to NSURLConnection. The problem is that I need to make multiple http requests, so having the same delegate (self) wont work.
What is the best way to go about this? Should I make a new delegate class for each http request? Are these delegates just NSObjects?
You have a few options. The two most most common are:
Make a new class for each connection (yes, a subclass of NSObject) and set them as delegates -- have them carry out whatever logic you need when the data is loaded
Set one class as the delegate and store references to all of your NSURLConnections. That way, when your delegate gets - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data called, you can test which NSURLConnection is being used (eg if ([connection == myConnection]) -- or whichever delegate method you're implementing)
What I do is make a class that will handle downloading a file, and notify me when it is done through a selector. I pass it a delegate, a selector and the Info it needs to perform the download.
- (void) downloadFileFrom:(NSString*) httpLocation respondAt:(SEL)selector on:(id)target withParam:(id)param
{
self.finishSelector = selector;
self.delegate = target;
self.responseParams = param;
}
the Class is its own NSURLConnection delegate. Therefore the instance is separated from the others that I may instantiate, And it handles creating its own result for me to work with. I hold onto the param object. which could be anything.
At the end of the download it does a performSelector: on the delegate. passing itself to the delegate.
if ([self.target respondsToSelector:self.selector])
{
[self.target performSelector:self.selector withObject:self.param];
}
then you can create an instance of the downloader and call your method... telling it where to reply to you.
MyDownloader downloader = [[MyDownloader alloc] init];
[downloader downloadFileFrom:#"http://www.mydomain.com/myimage" respondAt:#selector(myFileIsComplete:) on:self withParam: downloader];
[downloader autorelease];
another option is to create a #protocol for your class to respond at, and have you delegate conform to the responder.
That should work, but there is another option to consider. You could make a generic class that creates and calls the NSURLConnection provided they are common enough. Then keep an NSArray or NSDictionary of the classes. One for each connection.
Example: I have an app that needs to download several photos simultaneously. Therefore, I have a GetFlickrPhoto class. It has a custom init method that receives the URL and any other necessary info. Each individual class creates the NSURLConnection and can safely set the delegate to self
This helps keep things contained and very manageable/reusable.
To take it a step further:
The app I mentioned before, also needed to download JSON feeds. So I made a GenericDownload class that took in URL and asynchronously downloaded the NSData and then returned the NSData to the calling delegate via defined success/failure protocols. It didn't care what the NSData contained.
I remodeled GetFlickrPhoto to call GenericDownload and use the returned NSData for a photo. I then made a GetJSON class that also called GenericDownload and parsed the returned NSData into a JSON feed.
Takes a bit more time but in the end you will be glad for maintenance and future projects.
So I'm writing a function that authenticates against an API that returns an XML document packed with things I'd like to pass. The function can make a synchronous call with NSURLConnection's sendSynchronousRequest method, quite easily. Yet, once this method returns, I need to instantiate an instance of NSXMLParser, initiate it with the data, let it parse, etc, etc.
What I'd like to do, is in my function (after sendSynchronousRequest returns), instantiate NSXMLParser, give it the data to parse, and in a single method call, get it to start the parse, and not return until the parse is over.
For example:
- (void) myFunction
{
/* other code */
NSData *returnedData = [NSURLConnection sendSynchronousRequest:authRequest returningResponse:&authResponse error:&authError];
MyParserClass *parser = [[MyParserClass alloc] initWithData:returnedData];
[parser parseData];
}
In the above example, MyParserClass is a NSXMLParser delegate, and does all the parsing in the usual, delegated fashion. parseData will start the parse, and not return until it is over.
In what manner should I write parseData? A block-approach?
EDIT: I just remembered the -parse function in NSXMLParser is synchronous. Still, i'd love to know if anyone could explain a way to do this in asynchronous classes of any sort.
I'd recommend writing a class that implements the NSXMLParserDelegate protocol (for example, MyParserDelegate). When the delegate methods get called by the parser, it should build up a data structure with the information you want to extract from the XML file. I'd call it as follows:
// create the delegate
MyParserDelegate *delegate = [[MyParserDelegate alloc] init];
// create the parser
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:returnedData];
[parser setDelegate:delegate];
// parse the file
if ([parser parse])
{
// the XML was valid and parsed without error
// now, do something with the data you extracted
// e.g., self.xmlData = [delegate xmlBasedDataStructureBuiltByDelegate];
}
else
{
// the XML was invalid
// handle the error
}
The functionality of MyParserDelegate depends entirely on what you want to extract out of the XML file. I'd recommend reading Apple's Event-Driven XML Programming Guide for more information.
Remember, if you want to use a synchronous NSURLConnection, you should do this on a background thread.