I have a custom made uiview class, and i have a dealloc with other releasing call within it.
In this custom uiview, I have 3 outlet of controls : buttons, textview etc. When the custom uiview deallocated, I received this error: Error for object 0x88782c0: pointer being freed was not allocated.
Inside the code, I have not release any of these outlet at all. When I removed those 3 outlet of release call, the error was gone. Do I need to deallocate those outlets.
[[[[NSBundle mainBundle] loadNibNamed:#"ParanoidView" owner:self options:nil] objectAtIndex:0] autorelease];
[self.view setFrame:CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height)];
[self addSubview:self.view];
The above code is add within the initWithFrame call to load the nib file.
There are many things wrong with your code.
[[[[NSBundle mainBundle] loadNibNamed:#"ParanoidView" owner:self options:nil] objectAtIndex:0] autorelease];
You cannot release or autorelease something you didn't retain. Period.
Related
I have been looking all over fo information on how to do this but have found nothing that I understand.
Basically I want to be able (from ViewController.xib) to load another XIB file on top of that view in a subview. This new subview should be manipulatable, so it can be moved around with multitouch gestures and/or swipe gestures.
I was trying to add a "view" object from ViewController, then load the other XIB into that subview object.
Hopefully someone can help. Thanks!
You should be able to accomplish what you want by making an instance of the other class in your ViewController, and then adding it as a subview to the current view controller.
MyOtherViewController *movc = [[MyOtherViewController alloc] init];
[self.view addSubview:movc.view];
As for handling the gestures, you could either handle them in the MyOtherViewController class, or make a container view and handle them it in your ViewController. Don't forget that they are subviews, and that any movement should be relative to their superviews.
The above code is almost right but except
UIView *newView = [[NSBundle mainBundle] loadNibNamed:#"MyNewXib" owner:self options:nil];
it should be
UIView *newView = [[[NSBundle mainBundle] loadNibNamed:#"MyNewXib" owner:self options:nil] objectAtIndex:0];
and in a view controller simply you can add
[self.view addSubview:newView];
You can define the subview in a xib by creating a xib (select File New... "user interface", "view").
You can load that view like this:
UIView *newView = [[NSBundle mainBundle] loadNibNamed:#"MyNewXib" owner:self options:nil];
That new view can now be treated like any other subview:
// assign it to a property
#property (strong, non atomic) UIView *viewFromXib;
#sythesize viewFromXib=_viewFromXib;
self.viewFromXib = newView;
// add it to your hierarchy
self.viewFromXib.frame = CGRectMake( /* this will start out 0,0 the size from the xib */ );
[self.view addSubview:self.viewFromXib];
// add gesture recognizer
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[self.viewFromXib addGestureRecognizer:tapGR];
... and so on
I want to load a view dynamically on click of a button.
Lets say view is 'MyView'
I declared it as
IBOutlet UIView *myView;
and connected it via interface builder from a myView.xib made.
I did not set property and synthesize for this view
Now what i want is to allocate this view a memory on click of a button
so i tried in button pressed method of my viewController
(void) buttonPressed1{
myView = myView = [[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
myView.frame = CGRectMake(30, 40, 200, 200);
[self.view addSubview:myView];
}
It was Successfully loaded. :)
Now i want to access this view in other button click..
so i wrote
-(IBAction) buttonPressed2:(id)sender
{
myView.alpha = 0;
[myView release];
}
so when i run this ---it works ok
on buttonPressed it adds that view on other click it fades out and releases that view.
But now when i again click on button to add view it says
modifying layer that is being finalized - 0x6807b60
then on clicking button 2 , it crashes...
Basically my requirement is to keep that view in memory only when it is used after it has been used, it should be deallocated..
so is above approach is good one or there is any other way to do it...
and what does that error mean????
! more query is
Here in above case....
Memory to myView is allocated at run time on click of button ????....
As when i am testing this via instrument in xcode, there is no allocations showing in graph on button click...
so please help me out...
Please help..
Thanks in advance
When you are releasing view : [myView release]; it is not removed from superview. Moreover : you should not release it as it was created as autoreleased object.
The solution could be next:
(void) buttonPressed1{
if (myView)
{
[myView removeFromSuperview];
}
myView = [[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
myView.frame = CGRectMake(30, 40, 200, 200);
[self.view addSubview:myView];
}
-(IBAction) buttonPressed2:(id)sender
{
myView.alpha = 0;
//[myView release];
}
I have these two pieces of code. The first one works perfectly:
UIView *tmp = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 60.0f, 296.0f, 44.0f)];
[self.dynamicView addSubview:tmp];
[tmp release];
The second one is pretty much the same, but the view doesn't show up.
CommentBox *commentBox = [[CommentBox alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 296.0f, 44.0f)];
[self.dynamicView addSubview:commentBox];
[commentBox release]; // Why does this remove the view?
If I remove the [commentBox release] the view surprisingly appears. But I don't see a different between these two code snippets.
The init for the CommentBox looks like this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Load the nib:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
self = [nibObjects objectAtIndex:0];
}
return self;
}
After thinking about Graham's answer I came up with the following solution:
I drag a new UIView (-> lets call it sub UIView) in Interface Builder in my main UIView
I give this sub UIView the correct size (because I cannot resize the main UIView, which is always 320x460)
I drag all my other elements in this sub UIView (so that all elements are attached to my sub UIView)
I give my sub UIView a tag number (Interface Builder -> View Attributes), e.g. "300"
In the code I do now the following within my -initWithFrame:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
UIView *subView = [[nibObjects objectAtIndex:0] viewWithTag:300];
[self addSubview:subView];
Hope that helps.
Update:
I just had another idea of doing it. Instead of the tag numbers you can also create a IBOutlet UIView *viewHolder in the CommentBox class and set the outlet in IB. Then in the initWithFrame: I do the following:
[[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
[self addSubview:self.viewHolder];
You're doing weird things in -initWithFrame:. I'm not 100% sure that it's causing the problem you report, but I'm pretty sure it's:
wrong; and
causing a memory leak.
I don't think replacing a view object with something dearchived from a nib in its -init… methods is a good idea. Either load the nib from a controller class, or have your initialiser load the object's subviews from the nib without replacing self.
I have a custom UIView called TiledImage which has a single property named tiledImage and a custom drawRect method. I add this view to my ViewController, but when the ViewController is deallocated the dealloc for this view is never being called, even though I am releasing the view and setting it to nil. What could be causing this? I don't have any other references to the view, so my understanding is that it should release correctly.
This is how I add the view to my view controller:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"tile" ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:imagePath];
self.backImageView = [[TiledImage alloc] initWithFrame:IMAGE_FRAME];
self.backImageView.tiledImage = image;
[self.view addSubview:self.backImageView];
[self.view sendSubviewToBack:self.backImageView];
[image release];
And in my ViewController's dealloc method I have this:
_backImageView.tiledImage = nil, [_backImageView release], _backImageView = nil;
That line of code is hit, but dealloc is never called on TiledView. Note that _backImageView is the var that the property backImageView uses.
Can someone give me ideas on what I may be doing wrong that is preventing the dealloc on the TiledImage object from being called?
If self.backImageView is a retain property, you have a memory leak - the TiledImage has a retain count of 1 prior to invoking the setter, 2 afterwards.
Your code for adding the view should look like e.g. the following instead:
TiledImage *imageView = [[TiledImage alloc] initWithFrame:IMAGE_FRAME];
self.backImageView = imageView;
[imageView release];
Can someone please school me on the proper way to load a view hierarchy from a nib file. I am using the loaded view as a template to stamp out a family of views and the current approach I am using is subtly broken. I don't appear to be copy-ing or retain-ing when I should be. Here's the relevant code:
// pageSet is a list of view tag numbers I'll be using
for (NSNumber *n in pageSet) {
NSUInteger viewTag = [n integerValue];
// Ingest the nib. Should there be a copy or retain here?
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RandomStripe" owner:self options:nil];
// Pull the view from the nib. Should there be a copy or retain here?
MyView *view = (MyView *)[topLevelObjects objectAtIndex:0];
// The view has a label as it's subview
UILabel *pageNumberLabel = [view.subviews objectAtIndex:0];
pageNumberLabel.text = [NSString stringWithFormat:#"%d", viewTag];
CGFloat xOffset = ((float) viewTag) * self.scrollView.bounds.size.width;
view.frame = CGRectMake(xOffset, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
view.tag = viewTag;
// Insert the view as a child of my containerView
[self.containerView addSubview:view];
} // for (pageSet)
This has be making my head hurt for while now?
Cheers,
Doug
If you use IBOutlets from within Interface Builder back to your code, things would be a little easier. That way as soon as you try to access the UIView outlet you have set up, it gets loaded, with all its children, and then the UIView's initWithCoder will get called (useful if you have subclassed it).
#property (retain, nonatomic) IBOutlet iiView *iiView;
Otherwise, I do this:
if (self.numberView == nil) {
NumberView *numView = [[NumberView alloc] initWithNibName:#"NumberView" bundle:[NSBundle mainBundle]];
self.numberView = numView;
[numView release];
}
(With an IBOutlet for numberView, I just go ahead and start using numberView instead of the code above)
In both conditions, all the subviews - the children - of numberView will get loaded at the same time. If I needed to access a label or button I would do an IBOutlet for those too so I won't have to traverse the view hierarchy looking for them.
IBOutlet UIButton *nextButton,
*stopButton1,
*stopButton2,
*infoButton,
*bitsonthegoButton;
IBOutlet UILabel *pointsLabel1,
*pointsLabel2,
*totalPointsLabel1,
*totalPointsLabel2;
I wasn't sure if the other answer was exactly clear on this point, but any IBOutlets you set up on your view will get wired in with that same loadNibNamed: call you are doing today. So in the header for that view, you'd declare IBOutlets for both myView and pageNumberLabel, then attach them to the File's Owner in the xib (and set File's Owner type to be the view you are calling loadNibNamed: from).
That's just to make your life easier. To answer the question you asked, the documentation for "loadNibNamed:owner:options" tells us:
You should retain either the returned
array or the objects it contains
manually to prevent the nib file
objects from being released
prematurely.
So the array is autoreleased, and all the objects in it are as well (which you would expect from a call returning an autoreleased array). Since you want to keep the view you would retain that - doing so would mean any subviews of the main view would be kept around as well, since a view will retain anything set as a subview. If you also retained the label that would cause a leak when you released the main view unless you also release the label at the same time (but there seems no point in doing that).
However note that when I say "retain the view", you are already doing so in the code you posted, simply by adding it as a subview to your container view - as noted the view retains subviews. MyView will be released if it's ever removed from the subview, so you'd want to retain it if you do that for any reason and want it kept around.
Nib loading memory management seems complex at first, but the rules are actually much simpler than it would seem.