iOS7 background fetch EXC_BAD_ACCESS - ios

I'm trying to implement a background fetch method to get new data, but it's giving me an error with an NSMutable Dictionary. Here's my code
In my appDelegate under performFetchWithCompletionHandler I have:
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
id topViewController = navigationController.topViewController;
if ([topViewController isKindOfClass:[viewController class]])
{
[(viewController*)topViewController autologin];
}
else
{
completionHandler(UIBackgroundFetchResultNewData);
}
This calls auto login in my view controller
- (void) autologin
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* username = [defaults valueForKey:#"username"];
NSString* password = [defaults valueForKey:#"password"];
[self login:username password:password];
}
Which then calls login
- (void)login:(NSString*)username password:(NSString*) password
{
NSDictionary *login = [[NSDictionary alloc] initWithObjectsAndKeys:username, #"username", password, #"password", NO, #"showNotification", nil];
NSOperationQueue* backgroundQueue = [NSOperationQueue new];
ch = [[backgroundProcess alloc] init];
NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithTarget:ch selector:#selector(runEvents:) object:login];
[backgroundQueue addOperation:operation];
operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(checkStatus) object:nil];
[backgroundQueue addOperation:operation];
}
Everything works if my app is running in the foreground and I call the login function, but with the performFetchWithCompletionHandler as soon as it hits
NSDictionary *login = [[NSDictionary alloc] initWithObjectsAndKeys:username, #"username", password, #"password", NO, #"showNotification", nil];
I get EXC_BAD_ACCESS. Any help would be appreciated!

Not sure why you are only crashing from the background. One error I see is that you can't use "NO" (a scalar BOOLEAN value) in a dictionary directly. NSDictionary objects can only contain objects. You need to convert the NO value to an NSNumber. With recent versions of Objective C you can use the syntax #(NO) to convert a scalar to an NSNumber. This is the equivalent of
[NSNumber numberWithBool: NO];
I doubt if that is the source of your crash, but it is an error in your code.
I don't know the object ownership rules of NSInvocationOperation off the top of my head. Since the introduction of GCD I haven't used NSOperations or NSOperationQueues. You might want to think about using GCD based calls instead.

Related

How to execute a block immediately in a function?

I search on the web, but what I found is not what I expect.
I have a function with a block inside, and this function return before doing the treatment into the block. So my function return nil...
NSString* returnTheFolder()
{
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
GTLServiceDrive *service;
__block NSMutableDictionary* titlesAndIdentifiers;
__block __strong NSString* rootFolder;
__block NSArray* allIdentifiers;
NSString* userDefaultValue = [userDefaults objectForKey:#"User1"];
titlesAndIdentifiers = [[NSMutableDictionary alloc]init];
service = [[GTLServiceDrive alloc] init];
service.authorizer = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:KeychainForName clientID:ClientID clientSecret:ClientSecret];
GTLQueryDrive *query =
[GTLQueryDrive queryForFilesList];
query.maxResults = 9999999;
query.q = #"'root' in parents";
[service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLDriveFileList* files, NSError *error) {
for (GTLDriveFile *folder in files)
{
if ([folder.mimeType isEqualToString:#"application/vnd.google-apps.folder"])
{
[titlesAndIdentifiers setValue:folder.identifier forKey:folder.title];
allIdentifiers = [[NSArray alloc]initWithArray:[titlesAndIdentifiers allKeysForObject:userDefaultValue]];
rootFolder = [allIdentifiers objectAtIndex:0];
}
}
}];
return rootFolder;
}
Which method can I use for execute a block immediately in my function ?
Thanks a lot everyone !!!
The Google library you are using is designed to be asynchronous - it is making calls to a web service and they can take an arbitrarily long time to complete. You must take this into consideration when thinking of a synchronous solution - you may block for an arbitrarily long time.
The best solution for you is to redesign your code so it to is asynchronous.
If you cannot make your code asynchronous for some reason then you can make an asynchronous call appear synchronous, but you must be careful. In essence all you need to do is use a semaphore: have the callback block to the asynchronous call signal the semaphore, and after making the asynchronous call wait on the semaphore. However for this to work you need to know that the thread you are waiting on the semaphore is not the same thread that will be used for the callback - or the callback will be blocked. You need to determine what guarantees the Google library makes about the thread the callback will be invoked on and write your code appropriately.
And if all that sounds too complicated go back to the first recommendation - make your code asynchronous!
HTH
Instead of returning a value like this.You can make a function that does not return anything and takes a block as an argument.
The block will take the value as a parameter.
Change your existing code to the code below
-(void)returnTheFolder:(void (^) (NSString *rootFolder))completion
{
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
GTLServiceDrive *service;
__block NSMutableDictionary* titlesAndIdentifiers;
__block __strong NSString* rootFolder;
__block NSArray* allIdentifiers;
NSString* userDefaultValue = [userDefaults objectForKey:#"User1"];
titlesAndIdentifiers = [[NSMutableDictionary alloc]init];
service = [[GTLServiceDrive alloc] init];
service.authorizer = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:KeychainForName clientID:ClientID clientSecret:ClientSecret];
GTLQueryDrive *query =
[GTLQueryDrive queryForFilesList];
query.maxResults = 9999999;
query.q = #"'root' in parents";
[service executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLDriveFileList* files, NSError *error) {
for (GTLDriveFile *folder in files)
{
if ([folder.mimeType isEqualToString:#"application/vnd.google-apps.folder"])
{
[titlesAndIdentifiers setValue:folder.identifier forKey:folder.title];
allIdentifiers = [[NSArray alloc]initWithArray:[titlesAndIdentifiers allKeysForObject:userDefaultValue]];
rootFolder = [allIdentifiers objectAtIndex:0];
completion(rootFolder);
}
}
}];
}
And then call like below
[self returnTheFolder:^(NSString *rootFolder){
NSLog(#"Root Folder = %#",rootFolder);
}];
Cheers.

Trouble with OAuth in Temboo

I am trying to authorize Twitter For a user in iOS and Temboo. Here is how I am attempting to do it.
In my SetttingsViewController class I have a button where the user can tap to begin the TwitterAuthentication. I have the InitializeOauth methods in a class called TwitterClient, and the FinalizeOauth methods in a class called TwitterFClient. Here are my classes.
TwitterClient.m
-(void)runInitializeOAuthChoreo {
// Instantiate the Choreo, using a previously instantiated TembooSession object, eg:
TMBTembooSession *session = [[TMBTembooSession alloc] initWithAccount:#"prnk28" appKeyName:#"Floadt" andAppKeyValue:#"9b9031d182d7441da05f8214ba2c7170"];
// Create the choreo object using your Temboo session
TMBTwitter_OAuth_InitializeOAuth *initializeOAuthChoreo = [[TMBTwitter_OAuth_InitializeOAuth alloc] initWithSession:session];
// Get Inputs object for the choreo
TMBTwitter_OAuth_InitializeOAuth_Inputs *initializeOAuthInputs = [initializeOAuthChoreo newInputSet];
// Set credential to use for execution
[initializeOAuthInputs setCredential:#"Twitter"];
// Set inputs
[initializeOAuthInputs setForwardingURL:#"floadt://success"];
// Execute choreo specifying this class as the choreo delegate
[initializeOAuthChoreo executeWithInputs:initializeOAuthInputs delegate:self];
}
// TMBChoreographyDelegate method implementation - handle choreo errors
-(void)choreographyDidFailWithError:(NSError*)error {
// Log error to the console
NSLog(#"Error - %#", error);
}
// TMBChoreographyDelegate method implementation - choreo executed successfully
-(void)choreographyDidFinishExecuting:(TMBTwitter_OAuth_InitializeOAuth_ResultSet*)result {
// Log results to the console
// NSLog(#"%#", [result getAuthorizationURL]);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[result getAuthorizationURL]]];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *callbackid = [result getCallbackID];
[user setObject:callbackid forKey:#"TwitterCallbackID"];
[user synchronize];
NSString *oauthtokensecret = [result getOAuthTokenSecret];
[user setObject:oauthtokensecret forKey:#"TwitterTemporaryOAuth"];
[user synchronize];
}
TwitterFClient.m
-(void)runFinalizeOAuthChoreo {
// Instantiate the Choreo, using a previously instantiated TembooSession object, eg:
TMBTembooSession *session = [[TMBTembooSession alloc] initWithAccount:#"prnk28" appKeyName:#"Floadt" andAppKeyValue:#"9b9031d182d7441da05f8214ba2c7170"];
// Create the choreo object using your Temboo session
TMBTwitter_OAuth_FinalizeOAuth *finalizeOAuthChoreo = [[TMBTwitter_OAuth_FinalizeOAuth alloc] initWithSession:session];
// Get Inputs object for the choreo
TMBTwitter_OAuth_FinalizeOAuth_Inputs *finalizeOAuthInputs = [finalizeOAuthChoreo newInputSet];
// Set credential to use for execution
[finalizeOAuthInputs setCredential:#"Twitter"];
// Set inputs
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *tCall = [user stringForKey:#"TwitterCallbackID"];
NSString *tTAuth = [user stringForKey:#"TwitterTemporaryOAuth"];
[finalizeOAuthInputs setOAuthTokenSecret:tCall];
[finalizeOAuthInputs setCallbackID:tTAuth];
[finalizeOAuthInputs setConsumerKey:TWITTER_CONSUMER_KEY];
[finalizeOAuthInputs setConsumerSecret:TWITTER_CONSUMER_SECRET];
// Execute choreo specifying this class as the choreo delegate
[finalizeOAuthChoreo executeWithInputs:finalizeOAuthInputs delegate:self];
}
// TMBChoreographyDelegate method implementation - handle choreo errors
-(void)choreographyDidFailWithError:(NSError*)error {
// Log error to the console
NSLog(#"Error - %#", error);
}
// TMBChoreographyDelegate method implementation - choreo executed successfully
-(void)choreographyDidFinishExecuting:(TMBTwitter_OAuth_FinalizeOAuth_ResultSet*)result {
// Log results to the console
NSLog(#"%#", [result getAccessTokenSecret]);
NSLog(#"%#", [result getAccessToken]);
NSLog(#"%#", [result getScreenName]);
NSLog(#"%#", [result getUserID]);
}
Those are the two client classes. I believe that in the Facebook example they are both combined would that be the suggested practice?
Anyway this is how the methods are called from within the SettingsViewController Class:
SettingsViewController.m
TwitterClient *twitter = [[TwitterClient alloc] init];
[twitter runInitializeOAuthChoreo];
When the user returns from the Web Browser is when I call the FinalizeOAuth Method. Here is how it is stated in the AppDelegate.
AppDelegate.m
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
NSString *daURL = [url absoluteString];
// NSString *instagram;
NSString *twitter;
twitter = [daURL substringWithRange: NSMakeRange (0, 16)];
// instagram = [daURL substringWithRange:NSMakeRange(0, 27)];
if ([daURL isEqual: #"floadt://success"]) {
TwitterFClient *fo = [[TwitterFClient alloc] init];
[fo runFinalizeOAuthChoreo];
}else{
[[InstagramClient sharedClient] handleOAuthCallbackWithURL:url];
}
return YES;
}
Im under the assumption that there is a much simpler way to do this and I would be open to drastic code change!
It looks like you have these values reversed:
[finalizeOAuthInputs setOAuthTokenSecret:tCall];
[finalizeOAuthInputs setCallbackID:tTAuth];
Also, in the finalize step you're specifying your Twitter credential, but then you're also doing this:
[finalizeOAuthInputs setConsumerKey:TWITTER_CONSUMER_KEY];
[finalizeOAuthInputs setConsumerSecret:TWITTER_CONSUMER_SECRET];
That's unnecessary, since those values are stored in your credential (as evidenced by your use of it in the initialize-oauth flow). You can remove those two lines altogether. If they for some reason didn't match, your choreo execution would fail.

NSUserdefaults not updating till the application restarted

I am pasring json data from a url and taking one of teh values to NSUserdefaults to use it it application view .
Example user will enter an unique code given to him and this code will be appended to the requested URL , accoridng to the requested code the json value will be changed .
At present when i enter code it is fetching and saving NSuserdefaults and passing it to the label filed in view . But when i enter new code and fecth new data it is not updating in the view . If i restart the application and enter new code then it is showing new Value . Can somebody help me . here is the code
NSString *jsonUrlString = [[NSString alloc] initWithFormat:#"http://mywebsite.com/json/code.php?user=%#",_opcodeField.text];
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
[_indicator startAnimating];
_indicator.hidesWhenStopped = YES;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//-- JSON Parsing
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"settings = %#",result);
for (NSDictionary *dic in result)
{
[[NSUserDefaults standardUserDefaults] setObject:[dic objectForKey:#"footer"] forKey:#"op_footer"];
[[NSUserDefaults standardUserDefaults] synchronize];
[_indicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
}
View code is:
(void)viewDidLoad {
[super viewDidLoad];
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
How can I show new values without restarting application . Is there any code to be added in view ? I can see json is fetching correctly newvalues when user entered new code
Thank you.
Are you sure viewDidLoad is the best place to add this code?.
Try to add your code in some method which is called more often. For debugging I usually add some button just to call a NSLog to see what happens.
Try this if you want to load the text all the time you come to the viewcontroller.
- (void)viewWillAppear:(BOOL)animated {
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
}
Or you can try this if you want to load it to a label after getting the new code.
- (void)updateLabel {
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
}
Hope this helps.. :)
Why not move this line...
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
to here (unless of course this is in a different class)...
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"settings = %#",result);
for (NSDictionary *dic in result)
{
[[NSUserDefaults standardUserDefaults] setObject:[dic objectForKey:#"footer"] forKey:#"op_footer"];
[[NSUserDefaults standardUserDefaults] synchronize];
[_indicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
}
//Update it straight away
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
Also bit confused why you are looping through dictionaries here? Is there more than one dictionary? If there is the last value will always be the one that gets stored in UserDefaults.
You are also stopping the animation in the loop as well?
The user defaults plist can take time to save and update. It doesn't happen instantly. Try triggering the call after a pause of some kind. Test with a button.
Edit: you can add an observer to the default so that you know it has updated - Cocoa - Notification on NSUserDefaults value change?

Show activity indicator when iOS app is loading data?

My iPhone app has to load 3 data sets when it is first opened. I have 3 view controllers, one for each data set. I notice that when I am on my real iPhone and first open the app and touch a view controller there may be a very long pause, I am assuming while the data is being loaded, but I am not sure.
Here is the relevant code in my AppDelegate:
#import "AppDelegate.h"
#import "MasterViewController.h"
#implementation AppDelegate
- (void)application:(UIApplication *)application performFetchWithCompletionHandler: (void (^)(UIBackgroundFetchResult))completionHandler
{
// Background Fetch for Employees
EmployeeDatabase *tmpEmployeeDatabase = [[EmployeeDatabase alloc] init];
[tmpEmployeeDatabase updateEmployeeData];
completionHandler(UIBackgroundFetchResultNewData);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Set Background Fetch Interval
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
// Take Database Name and get DatabasePath for later use
self.databaseName = #"employees.db";
self.databaseNameLocations = #"locations.db";
self.databaseNameContacts = #"contacts.db";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.databasePath =[documentDir stringByAppendingPathComponent:self.databaseName];
self.databasePathLocations =[documentDir stringByAppendingPathComponent:self.databaseNameLocations];
self.databasePathContacts =[documentDir stringByAppendingPathComponent:self.databaseNameContacts];
// See if we need to initialize the employee db
EmployeeDatabase *tmpEmployeeDatabase = [[EmployeeDatabase alloc] init];
if (![tmpEmployeeDatabase checkIfDatabaseExists]) {
[tmpEmployeeDatabase updateEmployeeData];
}
// See if we need to initialize the contact db
ContactsDatabase *tmpContactsDatabase = [[ContactsDatabase alloc] init];
if (![tmpContactsDatabase checkIfDatabaseExists]) {
[tmpContactsDatabase updateContactsData];
}
// See if we need to initialize the Locations db
LocationDatabase *tmpLocationDatabase = [[LocationDatabase alloc] init];
if (![tmpLocationDatabase checkIfDatabaseExists]) {
[tmpLocationDatabase updateLocationData];
}
return YES;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
And here is where I call one of the web services and load the data:
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
- (void)callWebService {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"xxxxxx" password:#"xxxxxxxxxxxx"];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
AFHTTPRequestOperation *operation = [manager GET: #"https://xxxx/mobile/mobilede.nsf/restPeople.xsp/People"
parameters: [self jsonDict]
success: ^(AFHTTPRequestOperation *operation, id responseObject)
{
NSMutableArray *employees = (NSMutableArray *)responseObject;
FMDatabase *db = [FMDatabase databaseWithPath:self.employeeDatabasePath];
[db open];
for (NSDictionary *dict in employees) {
BOOL success = [db
executeUpdate:
#"INSERT INTO employees "
"(id,fstNme,midNme,lstNme,fulNme,locNbr,supID,"
"mrkSeg,geoLoc,lvl,vp,ema,ofcPhn,mobPhn) VALUES "
"(?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
[dict objectForKey:#"id"], [dict objectForKey:#"fstNme"],
[dict objectForKey:#"midNme"], [dict objectForKey:#"lstNme"],
[dict objectForKey:#"fulNme"], [dict objectForKey:#"locNbr"],
[dict objectForKey:#"supId"], [dict objectForKey:#"mrkSeg"],
[dict objectForKey:#"geoLoc"], [dict objectForKey:#"lvl"],
[dict objectForKey:#"vp"], [dict objectForKey:#"ema"],
[dict objectForKey:#"ofcPhn"],[dict objectForKey:#"mobPhn"], nil];
if (success) {
} // Only to remove success error
}
}
failure:
^(AFHTTPRequestOperation * operation, NSError * error) {
NSLog(#"Error: %#", error);
}
];
[operation start];
}
[EDIT]
I forgot the part of the code where I called the
[EDIT]
One possible mistake is that I am using the same background queue for each of the three processes? See the #define kBgQueue at the top of this bit of code.
What is the best practice to handle this? Should I NOT put this on a background queue and alert the user to wait?
[Thank you. I changed this and recompiled. The first time the app starts the interface will freeze at some point, and you cannot do anything for 12 seconds or so, and then it comes out of it. Subsequently there are no pauses. As an example, when I first open the app I can get to my first view, Employees by Name, and if I touch it to list them it might go into the the list but be blank. So I will touch the navigation backward and then it stops for 12 seconds (or so) and then it will return to the main menu, and when I go back in there are the employees. And it never stops from then on out. I cannot figure out why if this is on the background que that it is holding up the interface. What could I run to try to determine when this is happening?]
If your app could not work without data put data processing in background and show some activity indicator to user. If your app could work without data let user do whatever he wants to do and after data is being loaded just reload UI with new data.

How to prevent a method from being called all the time

-(void) parseXML
{
[self performSelector:#selector(parseXML) withObject:self afterDelay:55.0 ];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://apikeygoeshere.com/data.xml"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *xmlString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *xml = [NSDictionary dictionaryWithXMLString:xmlString];
NSMutableArray *items = [xml objectForKey:#"TeamLeagueStanding"];
NSMutableArray *newTeamObjectArray = [[NSMutableArray alloc] init];
for (NSDictionary *dict in items) {
TeamObject *myTeams = [TeamObject teamFromXMLDictionary:dict];
[newTeamObjectArray addObject:myTeams];
}
NSNull *nullValue = [NSNull null];
NSNull *nullValue2 = [NSNull null];
[newTeamObjectArray insertObject:nullValue atIndex:0];
[newTeamObjectArray insertObject:nullValue2 atIndex:1];
NSLog(#"standingsdataaaaa %#", newTeamObjectArray);
}
I want to add a unbutton to my storyboard so the user can refresh the data whenever he wants, but i don't him to be able to do this more than once per hour,
Can anyone help me? Thank you.
Just in the action method or wherever you call to get the XML
setEnabled: NO and set an NSTimer to fire nod a date that is 3600 seconds from now.
When it fires, setEnabled:YES
It might be nice to create a visual indicator to the user like a counter.
EDIT: In order to account for the fact that you still want to run the parseXML method every 55 seconds with or without the button press, I'm changing my answer by putting the conditional in the IBAction method triggered by the button press instead of putting the conditional in parseXML:
Declare an NSTimer as a class variable. For example, at the top of your .m directly after your #synthesizes, declare an NSTimer:
NSTimer *parseTimer;
Then in the IBAction method triggered by the button press, only call parseXML if the timer is nil; and if it is in fact nil and the parseXML method is going to run, initiate the timer so it doesn't run again for another hour:
- (IBAction)buttonPressed:(sender)id {
// If the parseTimer is active, do call parseXML.
// (And perhaps fire an alert here)
if (parseTimer != nil) return;
// Otherwise initialize the timer so that it calls the the method which
// will deactivate it in 60*60 seconds, i.e. one hour
parseTimer = [NSTimer scheduledTimerWithTimeInterval:60*60 target:self selector:#selector(reactivateButton) userInfo:nil repeats:YES];
[self parseXML];
}
The deactivateParseTimer method should deactivate the timer and set it to nil so that parseXML may run again:
- (void)deactivateParseTimer {
[parseTimer invalidate];
parseTimer = nil;
}

Resources