I know there are many threads about this and i read them but i couldn't make it work. This is my code
#property (strong, nonatomic) UIImageView *advertiseView;
- (void)startShowingImage
{
_advertiseView = [[UIImageView alloc] initWithFrame:CGRectMake(80,320,150,97)];
_advertiseView.image = [UIImage imageNamed:#"blocksAd.png"];
[self.view addSubview:_advertiseView];
NSLog(#"startShowing");
}
- (void)stopShowingImage
{
NSLog(#"stopShowing");
[_advertiseView removeFromSuperview];
}
i put NSLogs to check whether the methods are called and they are, but the image after it's first shown never disappears.
Any advice about this?
If NSLog(#"stopShowing") is definitely being called, then the only problem I think you might be having that would lead to removeFromSuperview not working is that you're not making your change (a UI update) on the main thread.
Try this instead:
[_advertiseView performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:NO];
Check that both the addSubview and removeFromSuperView are called in main thread
Check that startShowingImage is only called once, otherwise you have orphaned UIImageViews that you can never remove
- (void)startShowingImage
{
if (self.advertiseView) {
self.advertiseView = [[UIImageView alloc] initWithFrame:CGRectMake(80,320,150,97)];
self.advertiseView.image = [UIImage imageNamed:#"blocksAd.png"];
[self.view addSubview:self.advertiseView];
NSLog(#"startShowing");
}
}
Use property syntax unless you specifically need otherwise to avoid problems
Related
I am fairly new to iOS development. I have the following code
#property (nonatomic, strong) NSMutableArray *myImages;
-(void) viewDidLoad
{
[super viewDidLoad];
self.myImages = [[NSMutableArray alloc] init];
UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image1"]];
[self.myImages addObject:image];
[image setCenter:CGPointMake(10, 10)];
[self.view addSubview:image];
}
-(void) viewDidAppear:(BOOL)animated
{
for (;;) {
for (int i=0; i<[self.myImages count]; i++) {
[self.myImages[i] setCenter:CGPointMake(300, 300)];
}
}
}
When I do this, the image shows up at point 10,10. However it doesn't get changed to 300,300. Can any one suggest what I am doing wrong.
If I do something like
[self.myImages[0] setCenter:CGPointMake(300, 300)];
before the infinite loop, that works fine. but in the infinite loop no luck.
This code is just a snippet and a lot of the code is missing, but you should be able to understand what I am getting at with this.
Thanks
You forgot to add the imageView to the array. Add
[self.myImages addObject:image];
... in viewDidLoad.
As a side note: It's not common to abbreviate identifiers in Objective-C. Use imageView instead of image. Code becomes much easier to read.
You probably don't want the infinite loop in viewDidAppear, too.
first i'm kinda new to ios too so i am not sure.
i think there are 2 options:
i am not sure if view did appear is the right method to change the image i would suggest view will appear. and if you really want the one you used maybe try dispatch_async in order to change the image on the main ui thread.
Maybe try for in loop? that why you will set itrator as UIimage and it will recognize the image. this is less likly to solve it but maybe...
I've wrote a class which gets an image from the camera. Its header is as follows:
typedef void(^ImageTakenCallback)(UIImage *image);
#interface ImageGetter : NSObject <UIImagePickerControllerDelegate, UIPopoverControllerDelegate>
{
UIImagePickerController *picker;
ImageTakenCallback completionBlock
}
-(void) requestImageInView:(UIView*)view withCompletionBlock:(void(^)(UIImage*))completion;
#end
As you can see, I'm trying to make something like that in client code:
[[[ImageGetter alloc] init] requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
}];
Here is how I've implemented ImageGetter:
-(void) requestImageInView:(UIView*)view withCompletionBlock:(ImageTakenCallback)completion
{
completionBlock = [completion copy];
picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
[view addSubview:picker.view];
}
- (void)imagePickerController:(UIImagePickerController *)picker_
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
[picker.view removeFromSuperview];
picker = nil;
completionBlock(image);
}
The problem is since I'm using ARC, the instance of ImageGetter is deallocated instantly after call for -requestImage..., so the weak delegate of picker becomes nil.
Which are common ways to resolve such a issue?
I can see some ways, however, none of them seems to be quite right:
retain ImageGetter from client code, for example, assign it to a strong property. The problems here are: I wont be able to release it by setting this property to nil right after I get image, because this will mean setting retain count of object to 0 while executing the method of this object. Also, I don't want unnecessary properties (well, it is not a big problem, but nevertheless).
disable ARC for ImageGetter and manually retain at start itself and release after sending image to callback.
make static manager ImageGetterManager, which will have method requestImage..., it will create ImageGetter instances, retain them, redirect the requestImage... call, get callbacks from them and release. That seems the most consistent way, but is not it a bit complex for such a little code?
So how can I build such a class?
You can handle that within the ImageGetter class by creating and releasing a "self-reference".
In a class extension in the implementation file, declare a property
#interface ImageGetter ()
#property (strong, nonatomic) id selfRef;
#end
In requestImageInView:, set self.selfRef = self to prevent deallocation.
In the completion method, set self.selfRef = nil.
Remark: Actually you can manage the retain count even with ARC:
CFRetain((__bridge CFTypeRef)(self)); // Increases the retain count to prevent deallocation.
CFRelease((__bridge CFTypeRef)(self)); // Decreases the retain count.
But I am not sure if this is considered "good programming" with ARC or not.
Any feedback is welcome!
If this issue is introduced when switching to ARC, I should just go for option 1, and define it as a strong property.
However the behaviour is a bit different than you described for option 1: Setting the property to nil, does NOT mean the object is instantly released, it will just cause a decrement of the retaincount. ARC will handle that fine, the object will be released as soon as all referenced objects have 'released' it.
You can use the following strategy:
ImageGetter* imgGetter = [[ImageGetter alloc] init];
[imgGetter requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
[imgGetter releaseCompletionBlock]; // With this line, the completion block will retain automatically imgGetter, which will be released after the release of the completionBlock.
}];
Inside your ImageGetter implementation class, create a method that you can call inside the block like this.
-(void) releaseCompletionBlock
{
completionBlock = nil;
}
I have a question. There may be a very simple solution to this question but I am not able to figure it out yet. If I use a property say #property(nonatomic, retain)UIView *mainView.
Now I synthesize it in .m file and release it in the dealloc method as following:
- (void)dealloc {
[mainView release], mainView = nil;
[super dealloc];
}
Then in my viewDidLoad, I'm allocating it and adding it as the subview of my self.view like following:
- (void) viewDidLoad {
mainView = [[UIView alloc] init];
.
.
.
[self.view addSubView: mainView];
}
Now I understand that at this point my mainView would have 3 reference counts (one from alloc, one because it's a retained property, and the third one when I added it to self.view), its parent controller would own it too.
Now, my question is if after adding my view to self.view, I release my mainView using
[mainView release];
My app crashes when I go back to the previous view as I am sending release to already deallocated object. Now my question is how am I overreleasing my view here. what am I missing because when I use following code it works fine and no crashes occur.
- (void) viewDidLoad {
UIView *newView = [[UIView alloc] init];
self.mainView = newView;
[newView release];
.
.
.
[self.view addSubView: mainView];
}
I know why this second viewDidLoad method works but what I dont know is why first one fails, I am supposed to release my view after adding it to self.view. Right?
NOTE: I understand that in the first viewDidLoad, I can use autorelease method to release the view that is being assigned to the ivar and it wont crash but the whole point is I am trying to reduce the use of autorelease as much as possible. And I am not using ARC at all
I would really appreciate the explanation and suggestions.
From your question:
Now i understand that at this point my mainView would have 3 reference
counts (one from alloc, one coz its a retained property and the third
one when i added it to self.view)
You didn't assign through the property but assigned directly to the instance variable, so there was no retain; only in ARC does assigning to the instance variable retain the value. So, do not perform the manual release.
In order for your #property to retain the mainView, you should use it as self.mainView and not just mainView. If you use the latter alone, it will not retain it. Basically if you call self.mainView = ... it is calling a setter method for mainView which does a [mainView retain]; internally. When you are directly assigning it, it wont execute this setter and retain will not be executed.
You should try it like this,
self.mainView = [[[UIView alloc] init] autorelease];
[self.view addSubView:self.mainView];
or as shown in your question.
UIView *newView = [UIView alloc] init];
self.mainView = newView;
[newView release];
[self.view addSubView:self.mainView];
You can also try using ARC for your project. Your code will look like this in ARC,
self.mainView = [[UIView alloc] init];
[self.view addSubView:self.mainView];
Check the documentation for more details.
In your first viewDidLoad method you are not referring to self.mainView only mainView thats why its not retained, in order to retain property work you have to set mainView using self.mainView!
The problem is simple to explain but difficult for me to resolve. I have a property that is NEVER initialized.
First of all, I'm using the iCarousel custom class in order to display some images for my app. In one of its delegate methods (the one that it uses in order to know which view is going to show at some index), I use this code:
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
if(!view)
{
CustomController* controller = [self.storyboard instantiateViewControllerWithIdentifier: "identifier"];
//BTW, the CustomController is initialized properly. Its instance is not nil after the initialization.
controller.imageView.image = [UIImage imageNamed: "something.png"];
view = controller.view;
}
return view;
}
As you can see, the view that I show in my carousel is a custom view with its own controller. I initialize it using the storyboard method and then I just set the image in my imageView property, which is, obviously, an UIImageView.
Don't get excited and say that I'm not initializing my imageView, because I have a custom getter in my "CustomController" class. Like this:
//interface (.h)
...
#property (nonatomic, strong) UIImageView* imageView;
...
//implementation (.m)
...
#synthesize imageView = _imageView;
...
- (UIImageView*) imageView
{
if(!_imageView)
_imageView = [[UIImageView alloc] init];
return _imageView;
}
...
Believe it or not, even if I put a breakpoint in the "_imageView = [[UIImageVIew alloc] init];"... the program executes that line but the _imageView remains nil. ¿Why?
I don't want to know "How to set my property", so please don't give workarounds for this... what I want to know is "Why my property is never setted and remains nil always", what's am I doing wrong?.
I've also tried to use my imageView as an IBOutlet... but even if I link it to an imageView in the Interface Builder and check its value after the "viewDidLoad", it still remains nil.
P.S: Btw, I'm using ARC (yeah, I know is in the title... xD)
Well, it looks like the answer was what borrrden said, the problem was the LLDB debugger. Actually, my property was initialized but the debugger didn't detect it like that, if I change it to GDB I could see it wasn't nil after all. Furthermore, the reason why I had also issues with my child viewcontroller's outlets was because I didn't use the View Controller Container methods in iOS5 (DidMoveParentViewController and those ones).
Kinda tricky.
I am new to iPhone programming and Objective-C.
I am building a View-based application.
The problem is that none of the UIViewController's dealloc functions are ever called.
I have decided to unload all my retained objects programmaticaly, right before presenting the next UIViewController class.
I have resolved all the leaks detected by Xcode, tested the application with Leaks and Allocations Tools and everything seams OK, but the memory used builds up to around 180 MB and the app crashes.
The self.retainCount before presenting the next UIViewController is 1, the objects owned are released and the pointers are nil, but still the memory builds up.
Can you give me a clue? If needed I will post some code samples. Or can you send me some references to something like Objective-C memory management 101?
This is my interface:
#interface GameScreen : UIViewController
{
IBOutlet UILabel *timeLabel;
IBOutlet UIView *gameView;
IBOutlet UIImageView *gameViewFrame;
IBOutlet UIButton *showOutlineButton;
UIImage *puzzleImage;
UIView *optionsView;
UIView *blockView;
NSTimer *timer;
UIImageView *viewOriginalPicture;
SHKActivityIndicator *activityIndicator;
BOOL originalPictureShown;
BOOL outLineShown;
}
#property (nonatomic, retain) IBOutlet UILabel *timeLabel;
#property (nonatomic, retain) IBOutlet UIView *gameView;
#property (nonatomic, retain) IBOutlet UIImageView *gameViewFrame;
#property (nonatomic, retain) IBOutlet UIButton *showOutlineButton;
#property (nonatomic, retain) UIImage *puzzleImage;
And here is the implementation:
- (id) initWithPuzzleImage: (UIImage *) img
{
if((self = [super init]))
{
puzzleImage = [[UIImage alloc] init];
puzzleImage = img;
}
return self;
}
This is the function called when the user taps the exit button:
- (void) onExit
{
[timer invalidate];
CurrentMinuts = 0;
CurrentSeconds = 0;
//remove piece configurations
[pieceConfigMatrix removeAllObjects];
[pieceFramesMatrix removeAllObjects];
PuzzleViewController *modalView = [[PuzzleViewController alloc] init];
[self unloadObjects];
[self presentModalViewController:modalView animated:YES];
[modalView release];
}
And the unloadObjects function:
- (void) unloadObjects
{
[self resignFirstResponder];
[viewOriginalPicture release];
viewOriginalPicture = nil;
[timeLabel release];
timeLabel = nil;
[gameView release];
gameView = nil;
[originalImage release];
originalImage = nil;
[gameViewFrame release];
gameViewFrame = nil;
[timer release];
[showOutlineButton release];
showOutlineButton = nil;
}
I have a lead of what I do wrong, but I am not sure. Let me explain. I am adding the puzzle pieces to the 'gameView' property. For this, I have a 'SplitImage' object. The following function is called in - (void) viewDidLoad:
- (void) generatePuzzleWithImage:(UIImage *) image
{
SplitImage *splitSystem = [[SplitImage alloc] initWithImage:image andPuzzleSize:gPuzzleSize];
[splitSystem splitImageAndAddToView:self.gameView];
[splitSystem release];
}
Next, initialization function for the SplitImage class and the splitImageAndAddToView function:
- (id) initWithImage: (UIImage *) image andPuzzleSize: (int) pSize
{
if((self = [super init]))
{
UIImage *aux = [[[UIImage alloc] init] autorelease];
pieceCenterSize = [SplitImage puzzlePieceSizeForNumberOfPieces:pSize];
UIImage *outSideBallSample = [UIImage imageNamed:#"sampleHorizontal.jpg"]; //convexity size for puzzle size
outSideBallSample = [outSideBallSample resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:CGSizeMake(pieceCenterSize, pieceCenterSize) interpolationQuality:kCGInterpolationHigh];
outSideBallSize = roundf(outSideBallSample.size.height);
puzzleSize = pieceCenterSize * pSize;
pieceNumber = pSize;
if(image.size.height < puzzleSize || image.size.height > puzzleSize || image.size.width < puzzleSize || image.size.width > puzzleSize)
{
aux = [SplitImage resizeImageForPuzzle:image withSize:puzzleSize];
aux = [SplitImage cropImageForPuzzle:aux withSize:puzzleSize];
}
aux = [aux imageWithAlpha];
originalImage = [[UIImage imageWithCGImage:aux.CGImage] retain];
mainImage = aux.CGImage;
imageSize = CGSizeMake(aux.size.width, aux.size.height);
NSLog(#"%#", NSStringFromCGSize(imageSize));
splitImageSize = CGSizeMake(pieceCenterSize + 2*outSideBallSize, pieceCenterSize+2*outSideBallSize);
}
return self;
}
- (void) splitImageAndAddToView: (UIView *) view
{
for (int i = 0; i < pieceNumber; i++)
for(int j = 0; j < pieceNumber; j++)
//some code
UIImage *mask;
mask = [self randomlyRetriveMaskWithPrefix:1 forPieceAtI:i andJ:j];
CGImageRef split = CGImageCreateWithImageInRect(mainImage, cuttingRect);
PuzzlePiece *splitView = [[PuzzlePiece alloc] initWithImage:[UIImage imageWithCGImage:split] andMask:mask centerSize:pieceCenterSize objectMatrixPosition:i*pieceNumber+j outSideBallSize:outSideBallSize pieceType:pieceType pieceFrame:cuttingRect];
[pieceFramesMatrix addObject:[NSValue valueWithCGRect:cuttingRect]];
[splitView setTag:(i+1)*100+j];
[view addSubview:splitView];
CGImageRelease(split);
[splitView release];
}
Thank you,
Andrei
Objective-C memory management 101 is here:
https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Ignore the stuff on garbage collection, it isn't available for iOS.
It's not normal to release objects before presenting the next UIViewController.
Assuming you have a NIB, its contents will be loaded the first time that you (or the system) accesses the view member. Your view controller will get a call to loadView, then subsequently to viewDidLoad. If you have any views you want to add programmatically, you can do that in loadView or viewDidLoad, if you want to interrogate objects loaded from the NIB then you can do that in viewDidLoad.
Once loaded, the view will remain in memory unless and until a low memory warning occurs. At that point it'll be released. You'll get viewDidUnload. You should release anything view related that you've still got an owning reference to in there, and set to nil any weak references you may have.
Any attempt to access the view property subsequently will cause the NIB to be reloaded, etc.
So, when presenting a new UIViewController, just present it. If you create objects that are used only for display of that controller then do so on viewDidLoad, and release them on viewDidUnload.
That all being said, the Leaks tool in Instruments should be able to tell you which types of object are leaking and where you first allocated them, so it makes finding leaks really quite easy. The only thing to watch out for is that if one object handles its properties/members entirely correctly but is itself leaked then anything it creates will generally also leak. So when something leaks, check the thing that created it isn't also leaking before tearing your hair out over why you can't find a problem.
First, retainCount is useless.
Activity Monitor is pretty close to just as useless. As well, the behavior in the simulator can be quite different on the memory use front. Better to focus debugging of a problem like this on the device.
Next, this:
The problem is that none of the
UIViewController's dealloc functions
are ever called. I have decided to
unload all my retained objects
programmaticaly, right before
presenting the next UIViewController
class.
Any time you find yourself programmatically working around incorrect behavior, you are just creating more bugs.
Step back from your custom hack and figure out why the dealloc isn't being called. Something somewhere is over-retaining the object. The allocations instrument with retain tracking turned on will show you exactly where all retains and releases are sent to the errant objects.
Leaks likely won't show anything if whatever is retaining the objects is still reachable from a global or the stack (i.e. leaks are objects that can never be used by your program again -- but there are many more ways to explode memory use without it being truly a leak).
You should also "Build and Analyze", then fix any problems it identifies.
Next, if you are seeing memory accretion of repeated operations on the user's part, then Heapshot analysis is extremely effective at figure out exactly what has gone wrong.
Some specific comments:
puzzleImage = [[UIImage alloc] init];
puzzleImage = img;
2 bugs; you are leaking a UIImage and not retaining img. That your app doesn't crash in light of the above code indicates that there is likely an over-retain elsewhere.
retainCount is not a reliable debugging tool.
You should never pay attention to or rely on retainCount. Just because you released it does not mean that some part of the program does not still have a reference to it. retainCount has no value.
Generally as a rule of thumb. If you use 'alloc' you must 'release' at some point.
Unless ofcourse you have put it into an autorelease pool.
Leaks should be able to point you to the objects that are leaking, using that, narrow down to where those objects are added, stored etc.
Post examples of your code on how you instantiate objects and where you release them, you maybe doing something wrong early on.
edit: apologies, i put 'init' not 'alloc' previously, thank you dreamlax, early morning mistake.