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];
}
Related
I have a UIView designed in XIB file. Basically with a navigation bar and a button to close the UIVIew. I want to show this UIView in several UIViewControllers across the app.
Below is the code I have imp[emnted so far.However the UIView doesn't show up.
My ViewControllers are designed in storyboard however I needed a simple UIView that is why I created a new custom subclass of UIView alongwith a xib file of the same name.The File's Owner is also set to custom subclass. What else is required here?
#interface BottomSlidingView : UIView //this is my UIView
{
}
#implementation BottomSlidingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUserInteractionEnabled:YES];
NSLog(#"Bottom View Loaded"); //I get this log entry but the view doesn't showup.
}
return self;
}
- (BOOL)loadMyNibFile {
if (![[NSBundle mainBundle] loadNibNamed:#"BottomSlidingView" owner:self options:nil]) {
return NO;
}
return YES;
}
And this is how I call the custom UIView in my UIViewController.
-(void)shareButton:(UIBarButtonItem *)button
{
NSLog(#"share button clicked");
BottomSlidingView *bsv = [[BottomSlidingView alloc] initWithFrame:CGRectMake(20, 480, 280, 420)];
[bsv loadMyNibFile];
[self.view insertSubview:bsv belowSubview:self.optionsToolBar]; //this toolbar is a subview that I am adding to this view controller.
}
I see a couple problems with your approach:
Create the view instance from a nib file, rather than instantiating it with initWithFrame:. For example (if the custom view is the only root-level object in the nib file):
+ (instancetype)bottomSlidingView
{
return [[[UINib nibWithNibName:#"BottomSlidingView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
}
Implement awakeFromNib or initWithCoder: instead of initWithFrame: (which isn't called when loading from nibs) in your UIView subclass.
In your view controller, you would use something like the following to create the view:
- (void)shareButtonPressed:(id)sender
{
BottomSlidingView *slidingView = [BottomSlidingView bottomSlidingView];
[slidingView setFrame:CGRectMake(20, 480, 280, 420)];
[[self view] insertSubview:slidingView belowSubview:[self optionsToolBar]];
}
Hope that helps.
Where ever you want to reuse a UIView of a UIViewController in another view controller you need to use this....
YourViewController * child = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];//View controller of view , you want to reuse
[self.view addSubView:child.YourView]; //YourView = Name of view, you want to reuse
[self addChildViewController:child];
[child release];
After adding childViewController All IBActions will be work in child.
And after removing this view You have to remove YourViewController from parentViewController other wise there will be memory issues.......
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 have a very curious case (similar to this one):
I have a simple UITextView which is located in a UIView which I load programatically (NIB). Contents are loaded from a TXT file into the UITextView.text. This happens in the viewDidLoad.
Everything is fine if my text is only a couple of lines and if there is no need for scrolling. If the text is longer than the UITextView, however, the text will NOT BE DISPLAYED. Only if I touch the screen and try to scroll, will the text suddenly pop up.
I tried this nudge to get the text appear in the viewDidLoad:
textView.contentOffset = CGPointMake(0.0, 1.0);
textView.contentOffset = CGPointMake(0.0, 0.0);
But it won't work. I also made sure to call [super viewWillAppear] etc., but again, no luck. The only thing which helps a bit is if I init my view and load the text in the viewDidAppear. However, the last part of the UITextView is still not shown unless I scroll.
Any ideas why the UITextView is behaving this way? I have no clue and would be grateful for any suggestions as this is holding me up for days now.
EDIT:
I now know what is causing this strange behaviour, but I still don't know why this can be. The ViewController in which the PageView will be displayed is animated into view (simple animation block to slide the viewController into the screen). If I take away the animation, everything is fine. I have no idea why, though.
Here is a bit more code (not sure if it helps to clarify). This is the viewController where I init the view.
- (void)viewDidLoad {
[super viewDidLoad];
if (self.currentPageView == nil) {
NSLog(#"createPage...");
PageView *cpv = [[PageView alloc] init];
self.currentPageView = cpv;
[cpv release];
[self.view addSubview:currentPageView.view];
}
[self loadContentsFromTXTFile];
[currentPageView setTitle:title
date:date
text:text ];
}
This is the init of the PageView class:
-(id)init {
//self = [super initWithNibName:nil bundle:nil];
self = [super initWithFrame:CGRectZero];
if (self) {
[[NSBundle mainBundle] loadNibNamed:#"PageView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
-(void)setTitle:(NSString *)title date:(NSString *)date text:(NSString *)text {
UILabel *mytitle = [self titleOfPage];
[mytitle setText:title];
UILabel *mydate = [self dateOfPage];
[mydate setText:date];
UITextView *mytext = [self textOfPage];
[mytext setText:text];
}
Ok, I solved this by simply using a UINavigationController to handle the views in which the problematic UITextView was found. I still don't understand why this has caused problems, but if you experience this problem, there may be something wrong with the structure of your UIViewControllers and the way they refresh (or don't refresh) the UITextView.
I want to add a view from a nib file as a subview of my main view at the click of a button, but it has to be in a frame (0,108,320,351). I've tried the following code:
-(IBAction) displayJoinmeetup:(id)sender
{
[meetups removeFromSuperview]; //removing the older view
CGRect myFrame = CGRectMake(0, 108,320,351);
[joinmeetup initWithFrame:myFrame]; //joinmeetup declared in header file as IBoutlet UIView*joinmeetup
[self.view addSubview:joinmeetup];
}
This displays only a blank screen, otherwise if I remove the frame the subview displays covering the whole screen, how can I properly do this?
You should never call init... on an object after it has been created. If you can change a setting, there will be a setter for it. In this case, it is setFrame:
-(IBAction) displayJoinmeetup:(id)sender {
[meetups removeFromSuperview]; //removing the older view
CGRect myFrame = CGRectMake(0, 108,320,351);
[joinmeetup setFrame:myFrame]; //joinmeetup declared in header file as IBoutlet UIView*joinmeetup
[self.view addSubview:joinmeetup];
}
initWithFrame is not called for a view loaded from nib. See the UIView class ref for details.
You need to set the view size properties in interface builder (inspector).
You can try thi as follow:
-(IBAction) displayJoinmeetup:(id)sender
{
if(meetups)
{
[meetups removeFromSuperview]; //removing the older view
//also here you should release the meetups, if it is allocated
meetups = nil;
}
UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(0, 108,320,351)];
joinmeetup = tempView;
[tempView release];
[self.view addSubview:joinmeetup];
}
I suggest you try this:
[joinmeetup setFrame:CGRectMake(0, 108,320,351)];
[self.view addSubview:joinmeetup];
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.