How to retain variable in arc in every class - ios

I have a lot of classes which are sending requests and finally it all comes to SplitViewController. In the SplitUIviewclass I have to long poll and write the data in a table view. The long polling is done in the background thread, so I have declared a variable in app delegate, but when it comes to that it is nil. And the problem is whenever I try to access the NSMutablearray through the appdelegate, its coming as nil and the array is being released. My code for long polling is
- (void) longPoll {
#autoreleasePool
{
//compose the request
NSError* error = nil;
NSURLResponse* response = nil;
NSURL* requestUrl = [NSURL URLWithString:#"http://www.example.com/pollUrl"];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:)
withObject:responseData waitUntilDone:YES];
}
//send the next poll request
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData {
//i write data received here to app delegate table
}
If I call any other method in my SplitView class from data received, I'm losing control, also I cannot print my app delegate values in data received or the variables being released, I cannot call reload table or any other method from here.

Cant you set your properties in your ViewControllers as strong/retain like so
property (strong,retain) NSMutableArray *myData;
BTW, I learned a moment ago that it is bad practise to use your AppDelegate as a storage place for global containers. The ApplicationDelegate is a place for application delegate methods and for the initial setup of the foundation of your app; such as setting up the navigationController.
So consider storing your data in the appropriate place, perhaps core data or something else.

Related

how to table Reload ios when recieving response Data

Hi My problem is that i am getting a response from a web service and when i parse it and add to table and reload the table view it is not refreshing . Although if i call the [table reload] in keyboard is shown it gets updated there. Could someone tell me if im missing anything
This is what i am trying to do
- (void) longPoll {
//create an autorelease pool for the thread
#autoreleasepool {
NSLog(#"polling");
VSAppDelegate *var = (VSAppDelegate*)[[UIApplication sharedApplication] delegate];
//compose the request
NSError* error = nil;
NSHTTPURLResponse* response = nil;
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"polling response is %d",response.statusCode);
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:) withObject:responseData waitUntilDone:YES];
}
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData
{
//process the response here
NSError *error = nil;
NSLog(#"polling data is %#",[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]);
NSLog(#"polling data is %#",[[theData base64EncodedString]base64DecodedString]);
NSDictionary *notifDic= [NSJSONSerialization JSONObjectWithData:theData options:kNilOptions error:&error];
//VSViewControllerSplit *split = [[VSViewControllerSplit alloc]init];
[self RecieveFunction:notifDic];
}
try it
dispatch_async(dispatch_get_main_queue(), ^{
[tablrView reloaddata];
});
The dataReceived method doesn't appear to be calling reloadData. I'll assume that RecieveFunction method does, though, but you should confirm that. It's hard to say without seeing RecieveFunction.
The more fundamental issue would appear to be that dataReceived method is creating a new instance of VSViewControllerSplit, calling its RecieveFunction method, and then letting this new VSViewControllerSplit instance fall out of scope (and if using ARC, get deallocated unless you pushed to it, presented it, etc.). You presumably don't want to create a new VSViewControllerSplit every time longPoll calls dataReceived, but rather just reference the existing instance.

Having trouble with multiple NSURLConnection

I've looked around a lot and cant seem to find a proper answer for my problem. As of now I have a network engine and I delegate into that from each of the view controllers to perform my network activity.
For example, to get user details I have a method like this:
- (void) getUserDetailsWithUserId:(NSString*) userId
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#Details", kServerAddress]]];
request.HTTPMethod = #"POST";
NSString *stringData = [NSString stringWithFormat:#"%#%#", kUserId, userId];
NSData *requestBodyData = [stringData dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestBodyData;
NSURLConnection *conn = [[NSURLConnection alloc] init];
[conn setTag:kGetUserInfoConnection];
(void)[conn initWithRequest:request delegate:self];
}
And when I get the data in connectionDidFinishLoading, I receive the data in a NSDictionary and based on the tag I've set for the connection, I transfer the data to the required NSDictionary.
This is working fine. But now I require two requests going from the same view controller. So when I do this, the data is getting mixed up. Say I have a connection for search being implemented, the data from the user details may come in when I do a search. The data is not being assigned to the right NSDictionary based on the switch I'm doing inside connectionDidFinishLoading. I'm using a single delegate for the entire network engine.
I'm new to NSURLConnection, should I setup a queue or something? Please help.
EDIT
Here's the part where I receive data in the connectionDidFinishLoading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([connection.tag integerValue] == kGetUserDetails)
networkDataSource.userData = self.jsonDetails;
if ([connection.tag integerValue] == kSearchConnection)
networkDataSource.searchData = self.jsonDetails;
}
and after this I have a switch case that calls the required delegate for the required view controller.
Anil here you need to identify for which request you got the data,
simplest way to check it is as below,
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
// Check URL value for request, url for search and user details will be different, put if condition as per your need.
conn.currentRequest.URL
}
Try using conn.originalRequest.URL it will give original request.
You can do in many ways to accomplish your task as mentioned by others and it will solve your problem . But if you have many more connections , you need to change your approach.
You can cretae a subclass of NSOperation class. Provide all the required data, like url or any other any informmation you want to get back when task get accomplish , by passing a dictionary or data model to that class.
In Nsoperation class ovewrite 'main' method and start connection in that method ie put your all NSURRequest statements in that method. send a call back when download finish along with that info dict.
Points to be keep in mind: Create separte instance of thet operation class for evey download, and call its 'start method'.
It will look something like :
[self setDownloadOperationObj:[[DownloadFileOperation alloc] initWithData:metadataDict]];
[_downloadOperationObj setDelegate:self];
[_downloadOperationObj setSelectorForUpdateComplete:#selector(callBackForDownloadComplete)];
[_downloadOperationObj setQueuePriority:NSOperationQueuePriorityVeryHigh];
[_downloadOperationObj start];
metaDict will contain your user info.
In DownloadFileOperation class you will overwrite 'main' method like :
- (void)main {
// a lengthy operation
#autoreleasepool
{
if(self.isCancelled)
return;
// //You url connection code
}
}
You can add that operation to a NSOperationQueue if you want. You just need to add the operation to NSOperationQueue and it will call its start method.
Declare two NSURLConnection variables in the .h file.
NSURLConnection *conn1;
NSURLConnection *conn2;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
if(connection == conn1){
}
else if(connection == conn2){
}
}

How to save data out of an iOS completion block

I'm basically implementing a fancier NSURLConnection class that downloads data from a server parses it into a dictionary, and returns an NSDictionary of the data. I'm trying add a completion block option (in addition to a delegate option), but it crashes anytime I try to store that data in another class.
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
contentDictionary_ = data;
}];
I can NSLog that data just fine, and basically do whatever I want with it, but as soon as I try to save it into another variable it crashes with a really obscure message.
EDIT: the crash message is EXC_BAD_ACCESS, but the stack trace is 0x00000000 error: address doesn't contain a section that points to a section in a object file.
I'm calling this function in the init method of a singleton. It DOES let me save the data if I set this in the completion block.
[SingletonClass sharedInstance].contentDictionary = data
But then the app gets stuck forever because sharedInstance hasn't returned yet, so the singleton object is still nil, so sharedInstance in the completion block calls init again, over and over.
EDIT 2: The singleton code looks like this:
+ (SingletonClass*)sharedInstance {
static SingletonClass *instance;
if (!instance) {
instance = [[SingletonClass alloc] init];
}
return instance;
}
- (id)init {
self = [super init];
if (self) {
dataFetcher_ = [[DataFetcher alloc] init];
NSString *testURL = #"..."
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
[SingletonClass sharedInstance].contentDictionary = data;
}];
}
return self;
}
Like I said, this works fine but repeats the initialize code over and over until the app crashes. This only happens the first time I run the app on a device, because I cache the data returned and it doesn't crash once I have the data cached. I would like to be able to just say self.contentDictionary = data, but that crashes.
Specify a variable to be used in the block with the __block directive outside of the block:
__block NSDictionary *contentDictionary_;
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
contentDictionary_ = data;
}];
You're invoking recursion before ever setting the "instance". (which I now see you understand from OP).
In your block, you can use the ivar or an accessor instead of
[SingletonClass sharedInstance].contentDictionary
use:
_contentDictionary = [data copy]; or self.contentDictionary=data;
assuming that the ivar backing the contentDictionary property is _contentDictionary.
It sounds like you tried self.contentDictionary and it failed? I got it to work in a test, with ARC turned, so there may be something about your dataFetcher that is affecting this. In my test dataFetcher just returns a dictionary with a single element.
Turns out the issue was with a bunch of different parts. My URL was empty sometimes, and my data fetcher would just fail immediately and call the completion block. In my completion block I hadn't included any error handling, so if the singleton class hadn't initialized, it would repeat forever. With a real URL this doesn't happen.
I still would like to figure out why it crashes when I try to assign the data to an ivar, though.

iOS HTTP Request called twice

I have a function which makes GET request to the server. It works fine but for some reason it's called twice. I call function when a button is pressed.
This is function code:
-(void) GETasync: (NSString *) path{
receivedData = [[NSMutableData alloc] init];
NSURLRequest *request=[NSURLRequest requestWithURL:
[NSURL URLWithString: path]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
NSHTTPURLResponse * response;
NSError * error;
NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"data received");
}
So I see in output:
2012-03-07 16:36:41.509 KW2[24136:bf03] data received
2012-03-07 16:36:41.694 KW2[24136:bf03] data received
I also have a function for POST request and it's the same trouble with it.
I am assuming that you are printing out that log within your delegate method connection:didReceiveData:. That method can be called multiple times for one single connection - in fact it is commonly called at least twice.
From the documentation:
The delegate is periodically sent connection:didReceiveData: messages as the data is received. The delegate implementation is responsible for storing the newly received data.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
EDIT: I see that in your latest edits you have added that logging information (or maybe I did not see it right away - shame on me).
Are you possibly calling that method by a notification handler? If so, have you possibly double-registered for that notification -> hence your handler is invoked twice.
The problem was just in that I wired IBOutlets from File'Owner and First Responder to buttons in IB.
After removing wires from File's Owner, the method started to be called only one time.
Also make sure to check the IBAction connections for your button in Interface Builder. If you copy and paste buttons in IB, you can end up having 2 or more identical IBAction connections for a button, which would cause the method to be executed twice with just one button click.

iOS: sendSynchronousRequest with performSelectorInBackground

I need to make several https calls to a certain url. Therefore I do something like this
//ViewController Source
-(IBAction) updateButton_tapped {
[self performSelectorInBackground:#selector(updateStuff) withObject:nil];
}
-(void) updateStuff {
// do other stuff here...
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
[request setHTTPMethod:#"POST"];
NSData *postData = [[Base64 encodeBase64WithData:payload] dataUsingEncoding:NSASCIIStringEncoding];
[request setHTTPBody:postData];
NSURLResponse* response = [[NSURLResponse alloc] init];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//Process the recieved data...
//Setup another synchronous request
data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//Process data
//do this another 4 times (note for loop cannot be use in my case ;) )
//Finally update some view controllers
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationIdentifier" object:self];
}
So the problem with this code is that it crashes randomly (not always but frequently). I get no debugging output on the log. Sometime my whole app freezes or it simply crashes the whole program. But it never crashes if I run it on the main thread. Therefore I think the code is correct and I suppose now that it has something to do with the threading on the iphone.
What problems could happen when running the code this way and what might cause a random crashes?
Memory Management, you don't release your request or response objects after allocation.
Please re-check your code so you don't update any GUI in background thread. Also, it should be much better to use asynchronous processing.
The controllers or whatever are probably assuming they're receiving notifications on the main thread, which in your case they're not (and that's never a safe assumption to make). Have the controllers dispatch back to the main thread in their notification callbacks before they do anything with the data/updating the UIKit stuff, etc.
You should also put an #autorelease block around your entire implementation of -updateStuff.
Here's an example of a callback notification you might receive in one of your controllers:
- (void)updateStuffNotificaiton:(NSNotification*)note
{
// Can't assume we're on the main thread and no need to
// test since this is made async by performSelectorInBacground anyway
dispatch_async(dispatch_get_main_queue(), ^{
// relocate all your original method implementation here
});
}
Also note that if your implementation of -updateStuff is creating and manipulating data structures that your notification callback methods then access, it is important to properly guard those accessors. It's often better to pass the data wholesale back to the callbacks in the notification's userInfo dictionary.
An example of adding the autorelease notation to your -updateStuff method:
-(void) updateStuff
{
#autoreleasepool {
// do other stuff here...
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
[request setHTTPMethod:#"POST"];
// rest of method snipped for brevity
//Finally update some view controllers
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationIdentifier" object:self];
}
}

Resources