here i want to ask a question regarding view controller template for iphone or ipad.
question: i want to design a view controller with some images and make it as common template and need to use it as a template to other view controller too. (also some buttons and labels are the inclusions if needed)
(ie) when ever i call that class, automatically its components should be inherited to calling class.
is it possible?
it would be grateful if anyone answers me the suitable or favourable
I don't know how adMob works but like everything else you can create a BaseViewController in which you can add your adMob(in the viewDidLoad method) and then all the other viewControllers can subClass this BaseViewController. just call [super viewDidLoad]; in the viewDidLoad methods of your viewControllers and you will have it...
hoping this sorts your problem... :) this is what I usually do.
Sounds like you just need to derive your view controllers from a common base class. Is there something that you want to do that's not provided by inheritance?
Yes it is possible.
You need to create #property for your components to re use them in other class
in class1:
#property(nonatomic,retain) NSMutableArray *exercisesArray;
in class2:
#property(nonatomic,retain) NSMutableArray *array;
nextViewController *start = [[nextViewController alloc]initWithNibName:#"nextViewController" bundle:nil];
next.array = exercisesArray
Related
I want to do something like UITabBarController. UITabBarController has property viewControllers into which I can add instances of UIViewController * in IB. I'm trying to do the same think with my own VC:
#property (nonatomic, copy) IBOutletCollection(UIViewController) NSArray *viewControllers;
but this doesn't work. Is it even possible for us?
EDIT 1.
Ramshad posted the proper sample, but using XIB. I would like to achieve it using storyboards.
EDIT 2. - at the end of bounty worth...
I question vaderkvarn's post because in case of UITabBarController it works. Also as Ramshad posted, it is possible in NIBs. So far, dasblinkenlight's post is the most correct, but not answers the question. I'm holding this question opened because we shall find out if it's restricted for us or what is the way.
PS: Why these downvotes?
Although it does not look like you can connect UIViewControllers to IBOutletCollections (or there are too many restrictions placed on using them), there is a simple solution that works when you use storyboards. This code goes into your viewDidLoad method:
_viewControllers = [NSArray arrayWithObjects:
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller1"]
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller2"]
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller3"]
, nil];
The reason why the outlet collection solution does not work is that a View Controller is not an outlet. From the documentation:
An outlet is a property that is annotated with the symbol IBOutlet and
whose value you can set graphically in a nib file or a storyboard.
A view controller is not a graphical object.
If you want to use an IBOutletCollection, you should only use one view controller, and put the views in the collection.
But if you want one controller for every view, you need to go for a more programmatic approach. An array with view controllers might be a good start, but I couldn't say as I don't know what you want to do with them.
Edit:
To be more clear as you don't seem to catch my point:
No, it does not has to be a way. A Storyboard is not an API, it is a graphical tool for drawing scenes and segues. It is specially designed for things like Tab Bar based apps.
If you right click on your Storyboard file and choose open as -> Source Code, you will see that a Tab Bar Controller have special elements that other View Controllers do not have. To mess around with the XML in a Storyboard file is beyond me.
If you want to go with Nib files, use Ramshads answer.
If you want to get as close as possible with storyboards, go with dasblinkenlights answer.
But the answer to your question (as far as I know) is NO, there is no way to accomplish this with storyboards. If it were, it would have been documented, which it is not.
I have done your requirement using UISegmentedControl + IBOutletCollection + presentViewController.
You can use any control instead of UISegmentedControl as your wish.
I have Added 3 different UIViewControllers to Xib and labelled as ViewController1,2,3.
I also added 2 extra methods. One for presenting the corresponding view and another one for dismissing the earlier populated view.
I have attached the Xib settings screen-shot below.
You can use only one UIViewController instead of 3 and reuse it with some logic :)
The methods are below:
#property (strong, nonatomic) IBOutletCollection(UIViewController) NSArray *ViewCollection;
//dismissing the earlier populated view
- (IBAction)dismiss:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
//presenting the corresponding view.
- (IBAction)resetAction:(id)sender {
UISegmentedControl *mySegment = (UISegmentedControl *)sender;
int index = 0;
for (UIViewController *viewItem in _ViewCollection) {
if (index == mySegment.selectedSegmentIndex) {
[self presentViewController:viewItem animated:YES completion:nil];
}
index++;
}
}
You can download the my sample application from here
Xib Settings Screen-shot
UPDATE - Cause found!... please read below & suggest the solution:
While creating a video to show this issue, I have found why does that happen...
Any Control/Element that is defined between #imports & #implementation DetailViewController in .m file is lost by the original detVC when a new instance is created of VC.
Example:
I am including a video that re-creates this issue. As shown, all controls work except a UISegmentedControl & a UILabel.. both of which are defined in DetailViewController.m as:
#import "DetailViewController.h"
UISegmentedControl *sortcontrol;
UILabel *incrementLabel;
#implementation DetailViewController
Video Link - http://www.youtube.com/watch?v=2ABdK0LkGiA
I think we are pretty close.. Waiting for the answer!!
P.S.: I think this info is enough can lead us to the solution, but if needed I can share the code too.
EARLIER:
There's a detailViewController (detVC) in our app which is normally 'pushed' from a UITableViewController.
Now we are also implementing Push Notifications which would 'modally' present the same detVC whenever the notification arrives, which in turn can happen over any view controller.
It works all fine until the detVC through notification is presented while another instance of detVC was already the active view controller (pushed earlier through TableView).
The problem happens when the presented detVC is dismissed - the pushed detVC 'looses' control of about everything - It is not pointing to the same data as earlier & even the UISegmentedControl on Navigation Toolbar points to -1 index on pressing any index!
Why does such thing happen when we are creating a separate instance of detVC? Why does it affect the earlier detVC? How can it be resolved / What about Objective C needs to be learned here? (FYI, we are using ARC in the project)
Thanks
EDIT - Some code:
When Pushed:
ProductDetailViewController *detailViewController = [[ProductDetailViewController alloc] init];
detailViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:detailViewController animated:YES];
detailViewController.serverOffset=serverOffset;
detailViewController.prdctIndex = indexPath.row;
When presented through Notification:
- (void)displaySingleProduct:(NSDictionary*)userInfo{
ProductDetailViewController *onePrdVC = [[ProductDetailViewController alloc] init];
UINavigationController *addNav = [[UINavigationController alloc] initWithRootViewController:onePrdVC];
onePrdVC.justOne=YES;
onePrdVC.onePrdIDtoLoad=[[[userInfo valueForKey:#"prd"] valueForKey:#"id"] intValue];
[self.navigationController presentModalViewController:addNav animated:YES];
}
There is a Product class in detVC which gets the data from the values stored at the prdctIndex row in the SQLite table.
After dismissing the presented detVC through notification, the Product class of the pushed detVC starts pointing to the row which was used for Product class in presented detVC. And there is no such code in viewDidAppear which would alter Product class.
So, this, UISegmentedControl issue mentioned above & some other problems are causing the pain! Basically, the whole detVC acts weird - which re-works if we just pop & re-push it!
EDIT 2
I have more info on it which could lead to the cause.
If I run viewDidLoad on viewDidAppear like this:
if (!justOne) {
aProduct = [allProducts getProduct:(prdctIndex+1) one:NO];
[self viewDidLoad];
[self populateDetails];
}
the pushed detVC regains the control & every element/control starts re-working as expected (but not in the ideal way). So, it is quite clear that the separate instance of presented detVC does messes up the earlier pushed detVC & a re-setting up of all the controls / pointers is required through viewDidLoad.
Can any helpful conclusion can be derived from this info?
When in your code you write:
#import "DetailViewController.h"
UISegmentedControl *sortcontrol;
UILabel *incrementLabel;
#implementation DetailViewController
You are not defining these variables as instance variables (ivars), so they are not individual for each instance. There are three ways to define ivars.
1) The traditional way, in your .h file.
#interface DetailViewController{
UISegmentedControl *sortcontrol;
UILabel *incrementLabel;
}
2) Some additions to objective-C have added support for the next two ways. Like declaring them in your .m file.
#implementation DetailViewController{
UISegmentedControl *sortcontrol;
UILabel *incrementLabel;
}
3) If these ivars use properties to expose them, then you can simply leave out the explicit definition of them. So in .h:
#interface DetailViewController
#property (strong, nonatomic) IBOutlet UISegmentedControl *sortcontrol;
#property (strong, nonatomic) IBOutlet UILabel *incrementLabel;
and then in the .m file:
#implementation DetailViewController
#synthesize sortcontrol;
#synthesize incrementLabel;
Are you loading the view controller from a NIB? If so, it may be that the same instance of the view controller is used each time. You can log the address of your view controller in viewDidLoad and see if this is the case.
It actually depends on how your apps architecture has been created. If you are using TabBarController based application, here is the proper way to do so.
If two instances of the same class are interfering with each other, that strongly suggests that you are not storing all your state in instance variables. I would suspect that something in ProductDetailViewController stores its state in global or class data, and that your problem lives in there.
It's possible that you have done something silly like making ProductDetailViewController a forced singleton (overriding +alloc, which you should almost never do), but generally people remember when they've done that.
Never call viewDidLoad directly. That's only for the system to call. (I know you were just testing, but don't leave that in.)
But are you calling [super viewDidAppear:animated] in your viewDidAppear:? You have to call your superclass in that method.
I have this class (let's call it FooViewController) that's a subclass of UIViewController. It's supposed to act similarly to a UINavigationController, in that there's a rootController and you can add other UIViewControllers to it. And each UIViewController within FooViewController can create another UIViewController and push that new UIViewController to FooViewController.
Here's an example of what I mean. This is the auto-created code when you add a new UITableViewController to your project.
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"Nib name" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Here's the question: How can I have a variable like navigationController in all of my UIViewControllers? Just like you can add methods to existing classes using categories, can you also add variables to existing classes? It sounds like Associative References is what I'm looking for, but it's only available on a Mac.
One solution that would work for me is to subclass all the UIViewControllers that I might use, and have my actual classes subclass off of those. For example, I might do:
#interface FooUIViewController : UIViewController {
FooViewController *fooViewController;
}
#interface FooUITableViewController : UITableViewController {
FooViewController *fooViewController;
}
So that I could do: [self.fooViewController pushViewController:detailViewController];. But this seems like a dirty way of doing it.
I feel this shouldn't be a difficult thing to do and maybe I'm thinking about it wrong. Any thoughts? Thanks!
No, you can't add an instance variable to UIViewController.
Subclassing is not a bad way of doing it, considering more things it can do in relation to FooViewController. It doesn't harm the design of your classes because they depend on FooViewController anyway (just as the same as UIViewController having navigationController property).
Another way of doing it is to access the FooViewController object via the application delegate. But I think this is a dirty way of doing it (because they now depend on your application delegate).
I am writing a library to be used by developers for the iPhone (similar to the way that OpenFeint is implemented) and I am trying to create a ViewController with an associated XIB so that I can instantiate it in my code with
SplashScreenViewController *splashScreenViewController = [[SplashScreenViewController alloc] init];
UIWindow *topApplicationWindow = [self getTopWindow];
[topApplicationWindow addSubview:splashScreenViewController.view];
However, while this works with simple controls (UIButtons, etc), nothing shows up with my SplashScreenViewController. SplashScreenViewController is very simple:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface SplashScreenView : UIViewController {
}
#end
and the implementation is empty. In my View XIB (SplashScreenView.xib), I have tried setting the File's Owner's class to SplashScreenViewController which didn't work, then I tried it the way I've seen it done in OpenFeint which is to add a View Controller in IB and make the main UIView a child of it and make it of class SplashScreenViewController instead. That also does not work (does not display).
I'm wondering if anyone has a good idea for what I might be missing, or if someone can recommend a walkthrough for creating new ViewControllers the way that I'm attempting to.
Thanks!
Try 2 things :
Call initWithNibName not just init. Maybe the OpenFeint you were talking about were overriding the init to call initWithNibName , that's why you don't see it.
Set SplashScreenViewController as your file owner, and connect his view outlet to your
view in IB.
Hope it helps.
Instead of [splashScreenViewController alloc], try [SplashScreenViewController alloc]. I'm surprised you didn't get a compiler warning.
I am new to the iPhone SDK and am trying to create 3 views and switch between them. Data will come from a server and I will basically be showing 1 view and caching the other two. So far I am just trying to create a view and display it at run-time. My code is listed below. It shows only a blank screen and I think I am missing a key concept. Any Help?
#import <UIKit/UIKit.h>
#import "ImageViewController.h"
#interface Test5ViewController : UIViewController
{
IBOutlet UIView *rootView;
ImageViewController *curImage;
ImageViewController *nextImage;
ImageViewController *prevImage;
}
#property(nonatomic,retain) IBOutlet UIView *rootView;
#property(nonatomic,retain) ImageViewController *curImage;
#property(nonatomic,retain) ImageViewController *nextImage;
#property(nonatomic,retain) ImageViewController *prevImage;
#end
and
- (void)loadView
{
self.curImage = [[ImageViewController alloc]initWithNibName:#"ImageView" bundle:[NSBundle mainBundle]];
UIImage *pic = [UIImage imageNamed:#"baby-gorilla.jpg"];
[self.curImage assignImage:pic];
self.rootView = self.curImage.view;
}
and
#import <UIKit/UIKit.h>
#interface ImageViewController : UIViewController
{
IBOutlet UIImageView *image;
}
-(void)assignImage:(UIImage *)screenShotToSet;
#property(nonatomic,retain) IBOutlet UIImageView *image;
#end
Welcome to the iPhone SDK!
In general, there are two ways to get any view displayed.
First, and most commonly, you use a NIB file created by the Interface Builder. This is usually the easiest way to get started and I would recommend it for what you're trying to do here. It's too lengthy to describe all the steps you need to do for what you have here, but basically start in xcode by creating a new file and selecting "user interfaces" and choose View XIB. This will create a basic NIB file (they're called NIBs rather than XIBs for historical reasons). The first step in interface builder is to change the class name of the "File's Owner" to your UIViewController subclass (Test5ViewController). You can then drop anything that IB will allow into the view window or even replace the pre-supplied view object with one of your own. And here's the trick: make sure the view outlet (supplied by the UIViewController superclass) is connected to a view. Once this is done, this view will be automatically loaded when your NIB is loaded. You can then just put your UIViewController subclass (Test5ViewController) in your MainWindow.xib NIB file to get it automatically loaded, and you're in business.
Now, the way you're doing it here is the second way. Some people like to code this way all the time and not user interface builder. And while it's definitely necessary sometimes and always more flexible, it makes you understand what is happening a bit better. There may be other things, but the main thing you're missing is that in your code above, you have nothing that is adding your view into the view hierarchy. You need to check first that you have an UIApplicationDelegate subclass and it needs to load your "root" UIViewController class. All initial project creation types in xcode do this (except Window-based application). It is code like:
[window addSubview:rootController.view];
Once this is done, if your view controller wasn't loaded by the NIB (described briefly above), your loadView method will be called, expecting you to build your own view hierarchy. Above, you created the view(s), but failed to put them in a hierarchy. You need something like:
[self.view addSubview:curImage.view];
No view will be rendered until added to the view hierarchy. Make sure to look up the UIView class in the documentation and understand the variety of ways to add and remove views to the view hierarchy.
A couple things I should warn you about:
* your code above is leaking. You need to review how objective-C properties work. There's lots on this site about it. More than I have time to write about here.
* don't create a rootView property in the case you have here. There already is one in the superclass (UIViewController). It's just 'view'. Use that for saving your root view.
I hope this helps you get started. It can be bewildering at first, but you'll soon get it going! I recommend building and rewriting and rebuilding a lot of sample code before you do your "real" application. The SDK has many great samples.