iPhone refresh a view from another class - iphone

I want to be able to refresh a view from another class, but nothing I have tried is working. My application is a tabbed application with several tabs set up. I have a method called refresh in my ViewController1 class that looks like this
-(void)TestMe{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"widgjson" ofType:#"json"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
NSString *responseString = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString *docFile = [docDir stringByAppendingPathComponent: #"json.txt"];
[responseString writeToFile:docFile atomically:NO encoding:NSUTF8StringEncoding error:Nil];
[self loadView];
[self viewDidLoad];
}
This works fine. When the application first loads up, it loads a different json, then when I click this button it loads a new JSON and then updates the view. This is just temporary to test out refreshing. However if I try to call this method from another class, or from the AppDelegates ApplicationDidEnterForeground methods, nothing happens. I tried calling it like this
-(void)TestMe{
ViewController1 *vc = [[ViewController1 alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"widgjson" ofType:#"json"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
NSString *responseString = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString *docFile = [docDir stringByAppendingPathComponent: #"json.txt"];
[responseString writeToFile:docFile atomically:NO encoding:NSUTF8StringEncoding error:Nil];
[vc loadView];
[vc viewDidLoad];
}
So why does this method not work from any other classes. All I want to is to be able to refresh a view from another class or when the application loads up, but just can't seem to find anything that works.
Would be very grateful if someone could point me in right direction!
EDIT: UPDATING TO CLARIFY
Okay, what I have done for the time being which I don't like is put this
exit(0);
Inside AppDelegates ApplicationDidEnterBackground. This works to an extent, but is not an ideal solution.
What I would like to have happen is that when application is opened again, the AppDelegate gets run again which sets up the tabs. The JSON pulled from the server can affect the order of the tabs which is why I need the AppDelegates ApplicationDidFinishLaunching method to reload itself again.
Also I would like to know can I do this from another class in the application. The first time my application is loaded it asks for the users phone number, which is sent to the server which then generates an PIN. After this is done, then I want the AppDelegate method to load up and begin setting up the tabs and the order etc.

To prevent your application running in the background (and so to force reloading when you exit and re-enter) you can set the UIApplicationExitsOnSuspend key to YES in your info.plist.
However, this is probably a bit drastic.
Your current code for refreshing from the application delegate is a non-starter because you are creating a new instance of the view controller rather than talking to one that is on the screen.
For this reason it is best not to involve your application delegate at all in the process.
Instead, your view controller can register itself as an observer for the UIApplicationDidBecomeActive notification, and do whatever it needs to itself. You would typically register for this notification on viewDidLoad, and unregister on viewDidUnload (since, by definition, if you have unloaded the view, you don't need to refresh it when the app comes back up!).
You would register as follows (using blocks here as they are the future):
Declare an ivar of type id to hold the observer object, let's call it becomeActiveObserver in this case. So, wherever you are declaring your ivars, add id becomeActiveObserver. Then, in viewDidLoad:
becomeActiveObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidBecomeActive
object:nil
queue: nil
usingBlock:^(NSNotification *note){
//put your reloading code in here
[self TestMe];
}];
And remove like so in viewDidUnload:
[[NSNotificationCenter defaultCenter] removeObserver:becomeActiveObserver;
You can follow a similar pattern to pick up notifications (your own, or system ones) from anywhere else in your app. This is a better design than passing everything through the app delegate as it involves much looser coupling.

I guess clickMe is an action to a button.if you want to refresh the viewcontroller at startup then add a function in viewcontroller similar to clickme or any function that refreshes the view and call it from applicationWillEnterForeground method or you may try this :-
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"app will enter foreground");
[viewController clickMe:NULL];
}
and you may change the file in the applicationWillEnterForeground method of appDelegate if your application requires.

Related

Determining indexes in another ViewController

My NSMutableArray is from the NSCachesDirectory,I'm recreating/reloading the array in every VIEW. I'm displaying/preview it in UIScrollView which can be deleted in VIEW_A. In another ViewController VIEW_B, I have another preview of it, for another purpose.
What I needed is when I delete the image in VIEW_A, I will be able to determine in VIEW_B the deleted images or index. Because I'm using their indexes in VIEW_B. How can I be able to do it. I'm thinking of saving it all in NSUserDefaults but how.
Delete method:
[button removeFromSuperview];
[_buttons removeObjectAtIndex:button.tag];
[_images removeObjectAtIndex:button.tag];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"oneSlotImages%u.png", button.tag]];
[fileManager removeItemAtPath: fullPath error:NULL];
I just want to know/determine that indexes that are deleted from other view.
I'm not sure if i really understood your problem, but here's my response:
If you need to update some object after something change (like your array). You should use a pattern observer. You can get free one with NSNotificationCenter (in foundation lib), but i discourage it. You can use kvo/kvc but it's not as clean as if you'll do in a pattern observer.
By the way, you should use only one array, and if you need to perform change on it, use a specific controller to do it. (Not from the client side like in your UIViewA/B)
here on wiki how to use it (in java, but the skeleton is the same):
http://en.wikipedia.org/wiki/Observer_pattern
By the way NSUserDefault should be only used to store user preferences, not some app logic values.
Best option is to use a delegate method.
In VIEW_B set up a delegate protocol and in the delete method have a call to something like...
[self.delegate didDeleteImageAtIndex:button.tag];
then in VIEW_A before you push VIEW_B set it up as the delegate.
Then in VIEW_A have the method...
- (void)didDeleteImageAtIndex:(int)index
{
//delete image from VIEW_A's array
}

UIDocumentsInteractionController shows iBooks but doesn't open it

My UIDocumentsInteractionController is working as far as presenting an action sheet with a button that says "iBooks" but when I click on that button, it just dismisses and it doesn't take me to iBooks. Here's my code:
NSString *filenamePath =[NSString stringWithFormat:#"temp.%#", [[file path] pathExtension]];
NSString *docDir = [DataCenter getDocumentsDirectoryPath];
NSString *fullPath = [docDir stringByAppendingPathComponent:filenamePath];
NSURL *url = [NSURL fileURLWithPath:fullPath];
UIDocumentInteractionController *c = [UIDocumentInteractionController interactionControllerWithURL:url];
BOOL success = [c presentOpenInMenuFromBarButtonItem:buttonBack animated:YES];
What am I doing wrong?
Thanks
For those stuck at this: You don't need to set yourself up as UIDocumentInteractionController's delegate at all.
Problem was [UIDocumentInteractionController interactionControllerWithURL:url] is being autoreleased. It thought it would be retained internally by the action sheet being shown but apparently it's not.
So yea, gotta retain it until action sheet dismisses.
Try checking the UIDocumentInteractionControllerDelegate methods documentInteractionController:willBeginSendingToApplication: and documentInteractionController:didEndSendingToApplication:. If your view controller is the delegate of the document interaction controller, that should clue you in to where the problem may be.
Also, you should validate that the file you're trying to use elsewhere (a PDF I assume) is actually a what you expect it to be.

Objective-C Memory Issue

I'm having an issue with the memory management in my application. I have an NSDictionary instance variable that I'm setting equal to another NSDictionary that gets made in a method. This all works fine and my application behaves like I want it to, but I'm having trouble applying the proper memory management.
If I release the local dictionary it eventually causes a crash as the method is called repeatedly, because the data saved in the instance variable is also trashed. Here's the code:
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"Names" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.dictAllValues = dictionary;
[dictionary release];
Create dictAllValues using
#property(retain) NSDictionary *dictAllValues;
Your method
-(void) myMethod
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"Names" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.dictAllValues = dictionary;
[dictionary release];
}
and release in dealloc method
-(void) dealloc
{
[dictAllValues release];
[super dealloc];
}
How do you declare dictAllValues? Typically, it would be:
#property(retain) NSDictionary *dictAllValues;
If so, then the release in your code is correct and your problem lies elsewhere. Post the backtrace of the crash, use Build and Analyze and fix any issues, and try turning on Zombie detection.
From the apple memory management guide.
As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it.
So, in this case putting [dictionary release]; in dealloc method instead (or any other method you might use for clean up) should work fine.
I assume your dictAllValues property uses simple assignment, let me know if that's not the case.

Help with memory problem on iOS/iPad

In my app, I have a bunch of different image packs to download. The images are downloaded from my website one by one. The packs contain anywhere from 100-1500 images and each image is about 100KB-200KB.
When downloading the images, I have a method that selects the images to download, then I have a second method that does the actual downloading based on parameters sent from the main method. Here is the code for the download method:
-(BOOL) downloadImageName:(NSString *)imageName ImageGroup:(NSString *)imageGroup AndRow:(int)row {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSURL *downloadURL = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.website.com/%#_0001.jpg",imageName]];
NSData *data = [NSData dataWithContentsOfURL:downloadURL];
NSString *savePath = [NSString stringWithFormat:#"%#/%#^%#_%#.jpg",docsPath,currentServerCycle,imageGroup,imageName];
BOOL downloaded = [data writeToFile:savePath atomically:YES];
if (downloaded)
return YES;
}
else {
return NO;
}
}
The problem I am having is this:
When I run this with performance tools looking at allocations I'm seeing that the app is keeping mallocs (NSConcreteData) each time an image is downloaded and only releasing them when the main method (the one calling this download method) completes. Thats fine for the smaller image packs, but the larger ones are obviously crashing after my total allocations hit something like 300+MB (the normal amount of allocations in my app is about 3mb).
They arent leaking, because once the image pack is downloaded and the method ends, all the mallocs are gone.
I have tried manually allocing and releasing the NSData *data but it has no effect.
Perhaps the autorelease pool the objects are in is not being drained until the main method returns. You might try adding NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; at the beginning of your download method, then [pool drain]; right before you return from the download method. You need to make sure you release the pool before you return no matter where you return otherwise you'll leak the pool.
Also, just as a point of standard Objective-C style, your method should be named:
(BOOL)downloadImageName:(NSString *)imageName imageGroup:(NSString *)imageGroup andRow:(int)row
with lowercase letters to start the "imageGroup:" and "andRow:" argument names.

iPhone Memory Management with Properties of Singletons

I seem to have a fundamental gap in my memory management understanding. The code below is located within a singleton that gets called multiple times within my app to parse data that is downloaded from the web. For each article I download, I allocate a mutable string, then do tons of parsing, then write the file to the file system for later display in a UIWebView.
But every time I enter this method, I allocate a new "articleString". And I never release this string. I think this is a leak, but if I add a release at the bottom of this method (after the file is written), my app crashes the next time this method is called. I don't understand why it crashes, since another NSMutableString is allocated next time it is called.
UPDATE: I do release articleString in the dealloc method. But it still seems that I should release at the end of this method, since I alloc every time I enter.
UPDATE: articleString is defined as follows in the header:
#property (nonatomic, retain) NSMutableString *articleString;
the parseArticle method below is a placeholder for a series of methods that manipulate articleString.
self.articleString = [[NSMutableString alloc] initWithData:articleData encoding:NSUTF8StringEncoding];
//Parse the article for display
[self parseArticle];
//Write the article string to a file for later display
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"article.html"];
NSLog(#"%#", articleString);
[articleString writeToFile:path atomically:YES];
I like to let properties handle this for me. If the articleString property is set to retain then this is simple.
self.articleString = [[[NSMutableString alloc] initWithData:articleData encoding:NSUTF8StringEncoding] autorelease];
[self doStuff];
Then
- (void)dealloc {
self.articleString = nil;
[super dealloc]
}
article string will get released and properly retain when you set a new one. And it will be cleaned up on dealloc.