i have a small UIView, i fill it with some string data from net.
i want to it load just once. thats why i call it in appdelegate class.
CurrencyView *currView;
#property (nonatomic, retain)CurrencyView *currView;
in application didFinishLaunchingWithOptions:
CurrencyView *view=[[CurrencyView alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
self.currView = view;
[view release];
then i call it in every viewcontroller (in tabs).
AppDelegate_iPhone *delegate = [AppDelegate_iPhone sharedAppDelegate];
self.currencyView= delegate.currView
[self.view addSubview: currencyView];
when i move in tabs, currView moves from tab to other tab. when look back to the previous tab, currencyview is gone. it stays on the last tab. i dont know why.
what should i do for putting currview in all views?
You can't put an UIView to different controller at the same moment. When you add it to another controller / view, it will be removed from is previous one.
So you should re-add it when you change of tab ^^ (by using a delegate method, for example. It depends what you are using ;-))
I think there isn't another solution but if someone has a better idea it can interest me.
If you want to share the same view instance, you can retrieve the instance from the appdelegate in the viewcontroller viewWillAppear: method, check if the view's superview is not nil and eventually remove it from the superview, then add it to the current view. Something like this
-(void)viewWillAppear {
AppDelegate_iPhone *delegate = [AppDelegate_iPhone sharedAppDelegate];
CurrencyView *cView = [delegate currView];
if(nil!=[cView superview) {
[cView removeFromSuperview];
}
[[self view]addSubview:cView];
}
Maybe you can remove the currView from the superview in the viewWillDisappear: method rather than in the above.
Still, this remain very error prone and not very clean. It would be better if you just allocate two instance of CurrencyView and let them share the common data/model.
If you are low on memory, I doubt a single view will kill you app, but if that's the case there are other way to reduce the memory footprint, see the Apple's documentation on memory management and view controller lifecycle.
If what you want is a copy of the view, your #property statement for *cView should be
#Property (nonatomic, copy) UIView* cView;
if what you have instead is
#Property (nonatomic, retain) UIView* cView;
You are trying to share the same object in multiple views, which you can't do. With the former each time you grab it from the superview you will be making a copy of it, and I think that will work.
Related
I have information in a Master View which uses a UITableView object and a detail ViewContrailer that comes up after I push a user selection to it.
My challenge is with scrolling in a UITextView object, that doesn't go back to the top of the scrolling area on the detail View.
The user chooses a detail object from a list in the Master View Controller, then , brings it up in the detail ViewController. She then scrolls within the UITextView object - dogScrollingInfoTextView- on that view, going farther down so that upper lines don't show anymore. She then return to the Master View Controller, and selects a different row. Upon returning to the detail view, the new object's UITextView object (dogScrollingInfoTextView) is still positioned where the previous view left it.
The object being passed into this UITextView in the detailViewController, looks like this in the Master View Controller
self.detailViewController.dogScrollingInfo = dog.whatMakesDogSpecial;
In the original class definition, this property is declared like this
#property (strong, nonatomic) NSString *whatMakesDogSpecial;
The object used to transfer within the detailView controller class to the view are declared like this
#property (strong, nonatomic) NSString *dogScrollingInfo;
#property (weak, nonatomic) IBOutlet UITextView *dogScrollingInfoTextView;
and in the detailViewController implementation the transfer looks like this
self.dogScrollingInfoTextView.text = [self.dogScrollingInfo description];
I'm not sure if I should attach screen shots ?
Should I put in any other code? (I have put two methods below, one from each view controller class)
I can't find anything specifically related to scrolling in the UITextView Class or the UIView class, that tells me I have to do something programatically. This seems like it may have something to do with InterfaceBuilder. I'm using xib's NOT storyboards. But I can't find any choices in the different Inspectors that change this behavior.
Is configureView, which I use in the detail view controller class, perhaps not the right method to use for this? I think I found an example using the configureView method in the Xcode Master-Detail project template, though I built my application up from a Single View project template. And if not, how would I figure out what method to use?
I'm trying to learn to work with the apple documentation to solve challenges like this, but I find it hard navigating it. So pointers as to how to use the documentation better are much appreciated.
.... Code Snip from the Master View Controller class...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.detailViewController) {
self.detailViewController = [[HardlyWorkingDogsDetailViewController alloc]
initWithNibName:#"HardlyWorkingDogsDetailViewController"
bundle:nil ];
}
NSLog(#"The user selected dog #array position %d", indexPath.row);
Dog *dog = self.sortedDogDictionaryArray[indexPath.row];
self.detailViewController.dogName= dog.dogName;
self.detailViewController.dogLicense = dog.licenseString;
self.detailViewController.dogScrollingInfo = dog.whatMakesDogSpecial;
self.detailViewController.dogPhoto = dog.dogPhoto;
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
.... Code Snip from the Detail View Controller class...
-(void)configureView {
//NSLog(#"ConfigureView # 1 in detail vu");
if (self.dogLicense) {
self.dogLicenseUILabel.text = [self.dogLicense description];
self.dogNameUIText.text = [self.dogName description];
self.dogScrollingInfoTextView.text = [self.dogScrollingInfo description];
self.dogPhotoUIImage.image = self.dogPhoto;
}
}
Thank you
Laurel
Since you are reusing a HardlyWorkingDogsDetailViewController, this behavior makes sense. If HardlyWorkingDogsDetailViewController is light weight enough, there really isn't any need to reuse it. Simply reinstantiating it everytime should fix your problem:
self.detailViewController = [[HardlyWorkingDogsDetailViewController alloc] initWithNibName:#"HardlyWorkingDogsDetailViewController" bundle:nil ];
Dog *dog = self.sortedDogDictionaryArray[indexPath.row];
self.detailViewController.dogName= dog.dogName;
self.detailViewController.dogLicense = dog.licenseString;
self.detailViewController.dogScrollingInfo = dog.whatMakesDogSpecial;
self.detailViewController.dogPhoto = dog.dogPhoto;
[self.navigationController pushViewController:self.detailViewController animated:YES];
Although, having not seen your other logic, I can't say that won't introduce other bugs if any of your code depends on self.detailViewController only being created once (keeping a reference to it elsewhere, for example). If that is the case, or you just don't want to change the MasterViewController code, you can simple put the following in HardlyWorkingDogsDetailViewController:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.dogScrollingInfoTextView setContentOffset:CGPointMake(0, 0) animated:NO];
}
This makes it so every time the view is about to appear on the screen, the scroll view will get set back to the top. (viewDidLoad, viewWillAppear:, viewDidAppear:, viewWillDisappear:, viewDidDisappear: are part of UIViewController lifecycle and are very useful. You should read up on them)
On a side note, UITextView is implemented using a UIScrollView, so any scrolling method a UIScrollView has, the UITextView can do as well. More info here
I have looked on here and found a few examples but nothing works so here goes...
I have a subview which is started and works fine, the camera takes a pic and then a thumbnail appears at the bottom right, when clicked I want the subview released but no matter how I try I can't get rid of the subview!
Code:
-(void)onSingleTap:(UITouch*)touch {
NSLog(#"onSingleTap");
UIImageView *eyes = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"binocs.png"]] autorelease];
eyes.tag = EYES_TAG;
[self.overlayView addSubview:eyes];
[camera takePicture];
}
Then the thumbnail action:
- (void)thumbnailTapped:(id)sender {
self.view.alpha = 99.0f;
UIButton *binocsButton = (UIButton*)[self.view viewWithTag:BINOCS_BUTTON_TAG];
binocsButton.hidden = YES;
}
So my subView is called eyes and I just need to clear that view under the thumbnail tapped action. Any ideas would be fantastic!
I'm not sure I follow entirely, but don't you just want to add this to the bottom of thumbnailTapped::
[[self.view viewWithTag:EYES_TAG] removeFromSuperview];
By the way, rather than using tags it's probably better to store a reference to the views that you want to access as an ivar of your view controller class. I would add this to your property definitions:
#property (nonatomic, retain) UIImageView *eyes;
#property (nonatomic, retain) UIButton *binocsButton;
Then synthesise them and when you create those objects, assign to the properties and then you can access them easier later. Using tags I found in the past gets quite annoying as if the view is at the bottom of a complex view hierarchy you can't access it easily. If you do do this, remember to also release them in your dealloc (unless you're using ARC).
I have a simple question that I couldn't see it answered on the whole site,
One XIB file that has a UIView as the main,
in it has another UIView that's connected to one IBoutlet so I can assign it later to load a view from another XIB file. That assignment doesn't work.. it remains blank...
#interface Subclass : UIViewController {
UIView *view1;
}
#property (nonatomic,retain) IBOutlet UIView *view1;
#end
i linked view1 to the subview in the xib file
in implementation in initWithNibName I'm loading Other XIB file and use it's view and assigning it to the view1. Still this doesn't work...
detailControler = [[XibViewControler alloc] initWithNibName:#"XibViewControler" bundle:nil];
//one aproach
[self.view1 addSubview: detailControler.view];
//another aproach
[self setView1:detailControler.view];
If I'm adding the subview programaticaly to [self.view addSubview:detailControler.view] and set a frame to it, it will go fullscreen, and hide the original view.
I also had a different approach that didn't work
How to load multiple views on each button tap when using a UISegmentedVIew
This is how I usually set up a UIView inside another view, although I'm not entirely sure if it's best practice or anything like that:
if(newViewController == nil){
newViewController = [[NewViewController alloc] initWithCoder:nil];
}
newViewController.view.autoresizingMask = UIViewAutoresizingNone;
if([newViewController.view superview] == nil){
[view1 addSubview:newViewController.view];
}
Hope that Helps!
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.
I am trying to learn something basic and very important to develop decent iPhone apps. But I don't know enough to understand what I am not getting. Here's the question:
I have a window project, with 2 views - View1, View2. On each view (thru IB) I dropped an imageView control. When I call a function in view1 I want to set the image control (show an image) of View2.
How do I do that?
There must be a simple way but I haven't managed (and did search a lot) to find a straightforward simple way to do it or at least understand the concept.
Thanks in advance.
-mE
You don't necessarily need to share the image. Is it large? Are you downloading it? In other words, does it really need to be shared?
If it does, you can just instantiate the UIImage in your app delegate and pass it to each view controller when they are created. Set a property for each view controller for the image. Something like this:
ViewController1 *controller1 = [[ViewController1 alloc init];
[controller1 setImage:image];
[[self navigationController] pushViewController:controller1];
[controller1 release];
ViewController2 *controller2 = [[ViewController2 alloc init];
[controller2 setImage:image];
[[self navigationController] pushViewController:controller2];
[controller2 release];
Then in each view controller's viewDidLoad, you can set the image for your imageView's
- (void)viewDidLoad;
{
[super viewDidLoad];
[[self imageView] setImage:[self image]];
}
I'm not sure how you're a loading your view controllers, but the above code assumes you are using a navigation controller stack. If you need clarification for a different approach, let me know.
You should connect the UIImageViews in IB to outlets in your ViewController class. In your class's .h interface file, add as appropriate:
IBOutlet UIImageView *view1;
add a property:
#property (nonatomic,retain) IBOutlet UIImageView *view1;
and in your class implementation file (.m), synthesize the property:
#synthesize view1;
Finally, you need to connect the UIImageView object in IB to that new outlet. Then you can access the image property of the UIView within your class with view1.image