I am working on an iPad app and i utilise a UISplitview for my program.
Now on the main detail view of my program i have a uiscrollview on which i add two labels.
UIScrollView *scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(0,0, self.view.frame.size.width,self.view.frame.size.height)];
scroll.contentSize=CGSizeMake(320, 1600);
scroll.showsHorizontalScrollIndicator=YES;
scroll.backgroundColor=[UIColor clearColor];
[self.view addSubview:scroll];
This is the code i create on the first main page. Now imagine we push the second view, from that second view i can access everything by saying
[self.detailViewController.view addSubview:detailViewController.Image];
but when i try to add labels to the subview saying
[self.detailViewController.view.scoll...
but i cannot find the scroll object, BUT the background of the scroll set in the first view comes over in the second view. AND i cannot change the background of the first view.
I decided to make a second scrollview untop of the first (which works) but i much rather know how i can access the first view i created throughout the whole program since it would negate me having to waste space creating scroll views. but if i have to create all the views i need i want to be able to somehow delete or release them so the picture from scrollview one doesn't get transferred all the way too scrollview 3
Thank You
You have to create properties for all the variables that you want to access from other classes . So in your case
DetailsViewController.h
#interface DetailsViewController : UIViewController {
// class member variables here that can be accessed
// anywhere in your class (only in your class)
}
#property(nonatomic, strong)
//retain instead of strong if you are not using ARC or other types (weak, copy, readonly)
SomeClassThatYouHave *propertyThatCanBeAccessed
//declare here public instance methods
#end
In your DetailsViewController.m you will have:
#interface DetailsViewController (Private)
//declare private methods here or private properties
#end
#implementation DetailsViewController
#synthesize propertyThatCanBeAccessed;
//methods implementation here
#end
Now you can access the property of your DetailsViewController like detailsViewControllerInstance.propertyThatCanBeAccessed but you must alloc/init the instance.
Hope that this will give you an idea of class structure in the future.
Related
I'm learning iOS and am new to the concept of IBOutlets - so I'm making a simple app in an attempt to learn how it works.
The problem:
I created an interface using a Storyboard and want to hook it up to an IBOutlet in my custom class ("TapCounter") in order to access (and be able to set) its text field. However when trying to hook my class' #property (nonatomic, weak, readwrite) IBOutlet UILabel* numberOfTapsTextField;
up to the UILabel in the Storyboard the line does not want to attach to the label.
Here is an image of the situation: http://gyazo.com/0050ef0a78772adcad214cdc4603f932 (Dragging a line from the hollow circle next to the #property to the label in the Storyboard does not snap to it).
I have not modified anything of the boilerplate code except for that I added #import "TapCounter.h" in viewController.m
This feels like it should be a very simple thing - but again; I am new to this.
EDIT
Have I got this idea wrong? Should all IBOutlets be in the viewController of a view (and simply be accessed by other custom classes)?
It work like this:
create a CustomView class
add a view in you storyBoard
set class for this custom view as CustomView in identity inspector cmd+opt+3
Create an IBOutlate of your component inside customView
Link those component with respective outlet
Refer Image:
I recently asked a question regarding my incorrect use of instance variables on UIViewControllers. The answers I got brought to light another fundamental issue: I think I might be using UIViewControllers all wrong as well.
My typical storyboard looks something like this:
As you can see, each view controller has a custom class. One of those custom classes might look like this:
// SecondViewController.h
#import <UIKit/UIKit.h>
#import "MasterViewController.h"
#interface SecondViewController : MasterViewController
#property (strong, nonatomic) NSData *incomingData;
#end
// SecondViewController.m
#import "SecondViewController.h"
#import "ThirdViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// do stuff with data, then pass it on to next view controller.
}
#end
Each view controller is a subclass of MasterViewController. In MasterViewController, I'll usually put global things like user state validation, for example. That way every view controller in the app can validate user state without reimplementing it each time.
About that incomingData property...I wasn't sure how else to pass data between UIViewControllers without using a property on a custom class...hence three separate custom classes, each one not doing all that much.
So here's where it gets murky for me...
Should I be keeping important methods and instance variables in a "master" view controller so all other view controllers can subclass it and have access to those methods and variables? Or is that ridiculous?
Am I causing more work for myself by not using proper class extensions or categories? Would those help me keep things a little more streamlined and organized?
My current system works for the most part, but it can get unwieldy when I have lots and lots of view controllers, each with its own custom class.
Obviously, the first step which you may have done, and whether you've completely grasped or not, is to really understand the Model-View-Controller pattern. A pretty good tutorial I did with a quick google search is here: http://codewithchris.com/how-to-make-iphone-apps-mvc-one-pattern-to-rule-them-all/.
The next thing I'd suggest is that your controllers don't need to be subclasses of anything but UIViewController. There's a difference between the view hierarchy and the class hierarchy. In your storyboard, you're outlining a view hierarchy - which view/controller leads to the next view/controller. They can all be independent. They can still pass data even without being subclasses of each other, or of a previous controller.
You can still pass data directly through properties. Why not be more specific about what data needs to be sent? Instead of sending a generic NSData blob, specify what you need one controller to tell the next. For example, if you're passing in a username from one to the next, use:
#property (nonatomic, strong) NSString *username;
for the second controller, and in your first controller, set it:
self.secondController.username = #"my name";
If from the second controller to the third controller, you don't need the username, don't make it a property of the third controller. Maybe the third controller only displays a number:
#property (nonatomic, strong) NSNumber *someNumber;
From the second controller, just set its value:
self.thirdController.someNumber = #5;
Now, I like to use some global variables and methods. Those are sometimes useful when you have helper classes that don't need to be instantiated. One way to do this is to just have a class variable:
FirstController.h:
+(NSString *)defaultName;
FirstController.m
+(NSString *)defaultName {
return #"Default";
}
Then in second controller, you can do something like
self.username = [FirstController defaultName]
There are other patterns, like delegate patterns, where the second controller asks its delegate (the first controller) what the username should be:
self.username = [self.delegate username];
But for this you have to set up a protocol. Ray Wenderlich usually has very good tutorials: http://www.raywenderlich.com/46988/ios-design-patterns
What you have here is Strong coupling, which is considered to be a bad thing.
Lets say you want to create a new application, and you want to copy a view controller from the old application, at the moment it would be very difficult for you as you would have to modify a lot of things.
The goal is to achieve weak coupling, which means that every class in your project can work independently from one another.
You can store your data as a property on your App Delegate, which is a singleton, so you can get an reference from an any class using AppDelegate *appDelegate=[UIApplication sharedApplication].delegate;. Or you can define a new singleton object to store the data.
The pattern you are using is dependency injection, which many people prefer to the singleton pattern.
If all of your view controllers are inheriting from the same superclass (MasterViewController) and all have that same property then you can simply define the property in the superclass.
Previously I've been creating my views with interface builder.
When creating views with storyboards or nibs I would connect my outlets. I understand that the outlets are creating a strong connection to the properties on the view.
If I am creating views programmatically should my properties be strong?
.h
#interface LoginViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
.m
#interface LoginViewController ()
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
_loginView = [[UIView alloc] init];
_loginView.frame = self.view.bounds;
[self.view addSubview:_loginView];
//...
}
#end
A few things:
Your code isn't using the properties you defined
Don't put the private properties in the .h file
Don't state that your class conforms to the UITextFieldDelegate protocol in the .h file
As for whether the properties should be strong or weak I prefer strong but since you will be adding each of these properties (views) to the view controller's view, it would be fine to make them weak since there will always be a reference to them as long as the view controller is alive.
Your .h should just be:
#interface LoginViewController : UIViewController
#end
Your .m should be (assuming you do want to use the properties):
#interface LoginViewController () <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
self.loginView = [[UIView alloc] init];
self.loginView.frame = self.view.bounds;
[self.view addSubview:self.loginView];
//...
}
#end
When you use the strong attribute, you are basically writing retain, as in, you want Objective-C to allocate memory for the property and hold it until it is released.
That is all strong means.
This is only necessary if you are using ARC (though you can still use retain in ARC). If not, use retain.
"If I am creating views programmatically should my properties be strong?"
If they are objects and not primitives, then yes.
I recommend you to make properties with strong attribute if you want to create it manually not to use xib or storyboard.
As your code in initViewsAndLayout, if you always create a subview and add it to a view of a viewcontroller simultaneously in same method scope, there is no problem even if you use weak or assign attribute. addSubview will increase a reference count of the subview. But, I don't think it's such a good habit because all of us could make a mistake.
Therefore, you had better make a property of UIView with strong attribute.
You asked:
If I am creating views programmatically should my properties be strong?
Two part answer:
The view controller should definite maintain a strong reference to its top level view.
When not using NIBs or storyboards at all and doing everything programmatically, the root view is instantiated in loadView and generally stored in a retain/strong property. UIViewController already has a view property that bears the retain memory semantics, thats generally used. (For more information about programmatically created views, see the Creating a View Programmatically section in the Resource Management in View Controllers chapter of the View Controller Programming Guide for iOS)
(If you're not creating the root view in loadView and are instead instantiating the root view with a NIB or storyboard and are only programmatically creating the subviews, don't worry about the above discussion, as the NIB/storyboard takes care of all of that for you.)
For the subviews, when you call addSubview, the view is retained by its parent view. It's unnecessary for the view controller to also maintain strong reference to it as well. You can, but it is not necessary.
In my mind, the view owns its subviews, not the view controller. If one of these subviews is removed from its parent view, I don't think the view controller should be retaining it and it doesn't seem like good design that I have to remember to nil the property in the view controller, too. Worse, if I remove a container view that has nested subviews, I don't want to have to manually keep track of setting all of those individual properties in the view controller that I have to nil, as well.
Don't get me wrong: You can use strong with the subviews if you want/need. But I think it's incorrect to imply that it's ill-advised to use weak.
As a simple rule of thumb,
Any view is always owned (maintained by strong reference) by its
superview, when they are added to the superview.
A top-level view is always owned (maintained by strong reference) by its VC.
Now, a view can be added to its superview in two different ways,
When a view is created from code and added to some superview using addSubview: method. (This is what your question suggest).
When the view hierarchy is loaded from a nib file. (Here also implicit addSubview: calls are made by UIKit to create the hierarchy) and thus subviews are retained by strong reference their respective superviews.
So in either cases views are implicitly retained by their superviews and thus never get disposed until/unless the top-level view gets disposed by itself. So declaring strong properties for subviews imposes another ownership on the subviews:
An implicit ownership by its superview, and
An explicitly ownership by the property.
So in general, declaring strong property for subviews are not required, however it has been created (from nib / by code).
However, under some special situation declaring strong properties for views might be required. For example, when a view should be removed and re-added to its superview, the view should be declared as strong. When such a view is removed from its superview, the superview releases its ownership as well. So if we need to maintain a strong reference of that view if we need to reassign the same view again to some superview. In that case, a strong property reference to the view becomes handy and it disallows the view to be released.
PS:
When creating views with storyboards or nibs I would connect my
outlets. I understand that the outlets are creating a strong
connection to the properties on the view.
I found that there's merely a misconception, in your question. When creating view from storyboard/nib, outlets does not create any so-called strong connection with the properties. IBOutlets only describe how a property loads a view. In case of an outlet property, the view pointed by the property is unarchived and loaded if it has not already been loaded. However, its retention still depends on the strong/weak property accessor.
I am creating a simple iOS game that has a counter that tracks the users score and presents it in a UILabel in the corner of the screen. When something happens in the game it switches to a game over screen. I want to then display the contents of the label from the previous view in a label in the new view as the players score.
I feel there should be an easy way of doing this?
Thanks in advance!
The root cause of the problem is that you've embedded your game logic into your user interface. The score is not part of the user interface, but you've put it there anyway.
If your game is really simple, add a property to your app delegate that keeps track of the score. Each part of your user interface can access that property when it needs to.
As soon as you go beyond the most simple game possible, you should factor out your game logic into its own class. That class is responsible for managing the game state. Instantiate it when you start a new game, and you can pass it through to view controllers, create a shared instance, etc.
I'd recommend reading up on MVC.
Just make the label a #property and use self.navigationController.presentingViewController or something similar to access the first view controller:
#interface ViewControllerOne : UIViewController {
IBOutlet UILabel *myLabelOne;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabelOne;
#end
#interface ViewControllerTwo : UIViewController {
IBOutlet UILabel *myLabelTwo;
}
// myLabelTwo doesnt need to be a property, it could just be an ivar. Up to you.
#property (nonatomic, retain) IBOutlet UILabel *myLabelTwo;
#end
#implementation ViewControllerTwo
- (void)viewDidLoad {
[super viewDidLoad];
self.myLabelTwo.text = [(ViewControllerOne *)self.navigationController.presentingViewController myLabelOne].text;
}
#end
UINavigationController Class Reference
UIViewController Class Reference
Properties in Objective-C 2.0
Step away from your views for a second. Your labels and any other views are a place to present data, not to store it. What you want to share across screens is the score, which is part of your player's state.
Create a Player object. Give it a score property. Pass the same Player instance to the controllers of both views. Now you have a model shared by multiple controllers and presented in many views. Either controller can potentially update the model and the other with have access to the new state for display in their views.
I'm designing an iPad app where little UIScrollViews have their own UIViewController . Those controllers have in their view a button that call an IBAction method. But it isnt working, in fact, it doesnt seem that they are being pressed in the simulator.
Here is some code to give you an idea of what im am doing .
// In UIViewController A (say the parent or root that have several UIScrollViews)
MiniViewController * mini = [[MiniViewController alloc]init];
[scrollView1 addSubview:mini.view];
//repeat the same process a couple of times with different uiscrollsviews and instances of miniviewcontrollers
Now The MiniController is very simple as you can guess, i only post the .h file
#interface MiniControlador : UIViewController {
IBOutlet UIButton * button;
}
#property (nonatomic, retain) IBOutlet UIButton * button;
- (IBAction)doSomething:(id)sender;
#end
You can see that i used Interface builder to connect an UIButton "button" to a method called doSomething. But as i already said, it isnt working.
One more thing. I also tried to add a button to the UIScrollView with the Mini Controller instance programmatically.And it worked! But I certainly believe that it's extremely hardcoded.
What do you think? I'll appreciate any suggestion(s).
Apple's View Controller Programming Guide is an important read, and explains a lot about Apple's philosophy of one-view-controller-per-screen.
Much of the behavior of view controllers is built on the assumption that there is only one view controller operating at a time. When that assumption is violated, the behavior is undefined (or at least undocumented). In this case, your description suggests that the normal view controller behavior of inserting the controller into the responder chain between its root view and that root's superview (usually the previous screen) isn't working.
While you may find methods of initialization that do work properly, they're not going to be guaranteed to work, and the behavior is liable to change with future OS updates.
Edit: A relevant quotes from the View Controller Programming Guide:
Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy. In iPhone applications, the views in a view hierarchy traditionally cover the entire screen, but in iPad applications they may cover only a portion of the screen. The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
Thanks guys, I finally solve this using objects of a class (that I called GenericViewController). It actually acts like a regular UIViewController, the IBActions responds well to any event (i.e. buttons being pressed).
I used an IBOutlet UIView in order to contain UILabels, buttons...and so on.
Here is some code if anyone is interested.
#interface GenericViewController : NSObject {
/* Some IBOutlets here*/
//like a regular UIView of an UIViewController, this holds the rest of the outlets
IBOutlet UIView * view;
}
//some IBActions here
}
Then the UIScrollView only add the view of each GenericViewController object
[scrollView addSubview:genericViewControllerObject.view];
If anyone has a better solution, please let me know :)
Are you sure you are loading the view from the xib you made in InterfaceBuilder?
I'm doing something similar in my app, and it's working for me.
I'm implementing the init method like this:
- (id)init
{
if (self = [super initWithNibName:#"__your_xib_name__" bundle:[NSBundle mainBundle]])
{
// TODO: Add additional initializing here
// ...
}
return self;
}
If you are not loading the view from the xib, then there will be no connections made (no IBOutlets initialized and no IBActions triggered).