I've been trying to solve a problem to do with the image in my UIImageView being released due to memory warnings.
Here's my situation:
1) I declare a UIImageView in my .H:
IBOutlet UIImageView *fightStyleImage;
...
#property (nonatomic, retain) UIImageView *fightStyleImage;
2) I synthesize and dealloc in my .M:
#synthesize fightStyleImage;
...
...
-(void)dealloc{
[fightStyleImage release];
...
}
3) I attach the fightStyleImage to a UIImageView in Interface Builder.
4) Part of my app's experience allows a user to swipe on the device, to cycle through 5 different images. I am using the following code to achieve that:
// Load next image
UIImage *theImg = [UIImage imageNamed:#"fighter1.png"];
fightStyleImage.image = theImg;
Everything works really well, and I'm happy with the performance, experience, etc.
However, when I pop to another view controller (or to an MFMailComposeViewController, or an Address Book picker) and my device receives a memory warning (either through the simulator, or on the device), the following happens when I return to my original view controller: the iOS seems to jettison my UIImageView image (I assume because it is the most expensive object in memory), and I am left with a black screen (i.e. no image). If I begin to swipe again, the images return and continue to cycle properly.
I'd love to hear any thoughts on this, and thanks in advance for any solutions/insights anyone might have. In particular, I'm interested (of course!) in restoring my image that has been jettisoned from memory.
-SD
You need to properly implement the viewDidLoad and the viewDidUnload to setup and release your views. Read the iOS section of the Memory Management Programming Guide for assistance. I also recommend you move your IBOutlet declaration from the ivar to the property as so
UIImageView *fightStyleImage;
...
#property (nonatomic, retain) IBOutlet UIImageView *fightStyleImage;
The problem maybe due to using imageNamed: method as it caches the images into your memory and will be forced to free only when Low Memory warning occurs. Better go this way:
UIImage *image=[[[UIImage alloc]initWithContentsOfFile:imagePath]autorelease];
Related
If I have a subview built in Interface Builder, and I want to give it an actual name, I presume the only way to do this is to create a UIView instance variable in my view controller, and then do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.moveView=[self.view.subviews objectAtIndex:0];
self.moveView.backgroundColor=[UIColor redColor];
}
In so doing, I can now work with this subview using a conventional name, "moveView," rather than addressing it by its index number within the view heirarchy.
Is this is good way of doing something like this (outside of actually using a custom view class)?
Another way that is perhaps easier and does not require that you figure out the index number seems to be just creating a UIView #property IBOutlet and assigning that to the Interface Builder and doing this:
#property (nonatomic, retain) IBOutlet UIView * sensitivity;
in #interface.
However, I want to know if the "retain" quality of this #property means that my UIView is essentially using up double the memory, since doesn't the Interface Builder UIView also store this in memory? Or will hooking this up in IB make these one and the same, with just a singe actual UIView instance?
Yes, IBOutlets are a much better idea than referencing subviews by their index.
retain doesn't cause a property to copy an object on set—that's what the copy attribute is for—it just increments the object's retain count to "claim" it. I highly recommend reading the iOS Memory Management Guide if you haven't yet. Also note its section on nibs.
I am trying to figure out how to take a screen capture feed and send it to an iOS device (an iPad in this case) and have the images displayed on the screen, updating as each new image is sent while clearing the old one from memory.
I am just starting with the basics, so I am trying to get the simulator to load a screenshot from the desktop and display it on the screen, and then change the image as I take a new screenshot, and either delete the old one so I can rename the new screenshot to carry the same name or to simply overwrite the old one (thus the reference should still point correctly in the programming code).
I tried using a button that reloaded my UIImageView via:
- (IBAction)buttonPressed:(id)sender
{
[UIImageView setImage:ScreenCapture];
}
where ScreenCapture is the name of the UIImageView, with the hope that it would reload the existing referenced image.png file, but clicking the button simply exits that program within the simulator and goes back to the simulator's home screen.
Am I using the wrong object when trying to get this done via UIImageView? Is their an existing program/tutorial on this?
I would try to reverse engineer VNC for the iPhone, but both the copyright issues and the amount of advanced programming features are well beyond me.
Once I can get something working through Xcode, I am also planning on trying to implement the same thing via MonoTouch to see which language is easier to use and more beginner friendly.
Thank you for the help,
~Chris
header:
#import <UIKit/UIKit.h>
#interface Screen_Capture_3ViewController : UIViewController {
IBOutlet UIImageView *ScreenCapture;
IBOutlet UIBarButtonItem *Update;
}
#property (nonatomic, retain) IBOutlet UIImageView *ScreenCapture;
#property (nonatomic, retain) IBOutlet UIBarButtonItem *Update;
- (IBAction)buttonPressed:(id)sender;
#end
.m:
#import "Screen_Capture_3ViewController.h"
#implementation Screen_Capture_3ViewController
#synthesize ScreenCapture;
#synthesize Update;
- (IBAction)buttonPressed:(id)sender
{
[UIImageView setImage:ScreenCapture];
}
Everything else remains at the default when selecting "View-based Application", and I connected the ScreenCapture to the UIImageView in Interface builder, as well as Update and buttonPressed to the UIBarButtonItem in Interface Builder.
setImage is an instance method, not a class method, so you can't send it directly to UIImageView (nor would it really mean much).
Keep your current code from your question for the header (but only the property should be marked as IBOutlet):
#interface Screen_Capture_3ViewController : UIViewController {
UIImageView *ScreenCapture;
UIBarButtonItem *Update;
}
#property (nonatomic, retain) IBOutlet UIImageView *ScreenCapture;
#property (nonatomic, retain) IBOutlet UIBarButtonItem *Update;
- (IBAction)buttonPressed:(id)sender;
#end
In your implementation, your event handler should be something like this:
- (IBAction)buttonPressed:(id)sender {
UIImage* newImage = [UIImage imageWithContentsOfFile:#"pathToImage.png"];
[ScreenCapture setImage:newImage];
}
I'm using Interface Builder to build my rootViewController, which is retained by my application delegate. I have a few controls in this XIB such as a couple UIButtons, a UISlider, etc. as IBOutlets, hooked up properly in Interface Builder.
On the code implementation side of the XIB, I've seen some people use:
#interface RootViewController : UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
...
}
#property(nonatomic, assign) UIButton *button1;
#property(nonatomic, assign) UIButton *button2;
#end
Why do they use assign instead of retain? I've seen some people not even use an assign property.
Is it pointless to use retain since the rootViewController's XIB will always contain a reference to them as long as it is loaded? Or are they just being lazy and not going through the steps to retain, synthesize & dealloc? Seems to me like it can't hurt to keep a reference around as long as the control is needed and the viewController hasn't been dealloc'ed, but just wondering if XIB's do something differently where this wouldn't be necessary.
I've read the memory management guide, btw.
Thanks!
It cant hurt to keep all subviews as assigned instead of retained as long as they stay a child from there superview.
When you remove it from its superview and want to add it as a subview later on in your code. Thats not possible. When you remove it from its super its retain count will probably turn to zero. Thats one of the reasons why you use retain. Your controller object will then always be a owner of the view object.
I cant think of other reasons you must use retain instead of assign.
I always use retain, i think its a best practice for outlets and it seems to be a convention.
The context: I have three views. One Introductory view, an Upload view and the Main view. As classes (With their respective headers) I have the rootViewController (SwitchViewController), IntroViewController and UploadViewController. The first view to be shown is IntroView. The user presses a button (declared in SwitchViewController) that takes them to the UploadView, then in the UploadView they get to choose an image and press the button again to go back to IntroView.
The thing is that while the user gets to pick the image with UIImagePickerController the button to switch views won't hide nor a UIImageView I have with a logo on top of the view(screen). The UIImageView and the UIButton are both declared in SwitchViewController's header.
The code used:
UploadViewController.h
#import [...] //Imports
#class SwitchViewController;
#interface UploadViewController :
UIViewController <UIImagePickerControllerDelegate,
UINavigationControllerDelegate,UIActionSheetDelegate> {
UITextField *imageTextField;
UIImageView *uploadedImage;
SwitchViewController *switchViewController;
[...]
}
#property (nonatomic, retain) SwitchViewController *switchViewController;
#property (nonatomic, retain) IBOutlet UITextField *imageTextField;
#property (nonatomic, retain) IBOutlet UIImageView *uploadedImage;
[...]
#end
UploadViewController.m
[...]
- (IBAction) selectImageButtonPressed {
self.switchViewController.submitButton.hidden = YES;
self.switchViewController.imageLogo.hidden = YES;
[...] //continues
I just begun recently programming in objective-c so please forgive me if the question is very essential. I have looked and am following "Beginning iPhone 3 Development" of APRESS. But even if it helps to greatly understand the basics sometimes I get lost.
PS: If it is clearer to answer the question the SwitchViewController.h and .m snippet codes can be provided if asked. But I thought this text is big as it is.
#Joze i think I may have understood your problem switchViewController is a variable of the class UploadViewController so if you do anything with that variable it wont affect the switchViewController view. so when you are calling the switchViewController view at that time you have to do initWithNibName: bundle: and then hide the button and imageView and also you need to do something like switchViewController.delegate = self; and then call the view modally or what ever way you want it.
PS. i m not sure the that spelling is correct. i dont have xcode at my home.
I hope your problem solves with this.
I solved my problem after refactoring the whole code and changing the general structure of the program itself. Now I have 3 views and each with a viewController to control it. All the switching of views occurs in the Delegate since he has access to everyone. That way I can control every property with every controller, without much difficulty. Changing the property of one of the objects present in one view from another view is difficult and rather inconvenient if not sometimes impossible.
The approach I took when asking this question was short sighted for the application that had to be done. I thank all those who tried to help.
I encountered a weird behavior in memory just by displaying the default keyboard.
I've just created a project with an .xib file for testing purposes.
This .xib file has an UITextField element in it and it's connected in the .h via:
#property(nonatomic, retain) IBOutlet UITextField *sometext;
The .m has no changes but:
#synthesize sometext;
- (void)viewDidAppear:(BOOL)animated {
[someText becomeFirstResponder];
}
As you see it's very very simple.
The problem is that once the keyboard is shown, the memory allocated for it NEVER goes down.
I've tested this scenario in another project with the only difference of having two .xib files.
Standar pushViewController and popViewController calls are made. Instruments show an increase of 600kb in memory allocations [which are a lot more in the actual iPhone device].
All in all, hehehe. My question is:
How do I release the memory allocated for the keyboard?.
You don't. Is it a leak? If you are just looking at the Allocations, don't expect it to go back down.
EDIT:
Clarification - Object Allocations in Instruments will always go up. It won't go down. It doesn't show deallocations, just allocations...