I am trying to create a new control for Xcode to implement into a new iOS app. The end idea is to display the formation of a football squad graphically. I realise that this could all be coded programmatically but I want to create a new control to represent a player and then load the formation accordingly as I may add other player information to the control in the future.
I have created a xib view file, in which is a label for displaying their name. I have tried the following but the label's text doesn't show up. Am I missing something obvious?
[I have included the correct headers and have connected the label up and set the xib to the new class]
header file for xib:
#interface playerObject : UIControl
#property (nonatomic, strong) NSString *playerNameLabel;
#end
implementation file for xib:
#import "playerObject.h"
#interface playerObject ()
#property (strong, nonatomic) IBOutlet UILabel *nameLabel;
#end
#implementation playerObject
- (void) setPlayerNameLabel:(NSString *)playerNameLabel
{
self.nameLabel.text = playerNameLabel;
}
View Controller Implementation File:
- (void)viewDidLoad
{
...
playerObject *newPlayer = [[playerObject alloc] initWithFrame:CGRectMake(10, 10, 100, 150)];
[newPlayer setPlayerNameLabel:#"TEST"];
[newPlayer setBackgroundColor:[UIColor redColor]];
[self.view addSubview:newPlayer];
}
Thanks in advance!
You may have created a xib file containing a label however you do not appear to be using it. You are creating a new instance of the playerObject class instead of loading one from a xib file. Take a look at the UINib class documentation instead.
You are instantiating your custom view without loading it from the .xib file.
In order to make it work, follow these steps:
Make your playerObject inherit from UIView instead of UIControl.
Open your .xib file.
Select the root view on the left pane.
On the right pane, switch to the Identity Inspector tab.
Type playerObject into the first text field "Class".
Make sure that you connected all your IBOutlets within Interface Builder.
Do the following to load your custom UIView from the .xib file:
playerObject *newPlayer = (playerObject *)[[[NSBundle mainBundle] loadNibNamed:#"MyXibFilename" owner:nil options:nil] firstObject];
newPlayer.playerNameLabel = #"Lionel Messi";
Note aside: I strongly recommend you to start using "namespaces" for your classes (it's just a two-letter prefix), such as XXPlayerObject, with XX being something else you consider describes your app / module. All other related custom classes should "share" this namespace. Look at what Apple does with its classes.
I hope this helps you!
Related
I have a problem in my iOS application that I'm looking for some help with. I'm relatively new to iOS programming to I'm sure that there is some relatively simple solution to my problem.
First, I'm going to explain the hierarchy of the application:
It uses a UITabBarController to show a couple of different screens.
It uses a SWRevealViewController to show a sidebar
The sidebar is accessed from a Bar button item that is present in the Navigation bar of the application.
That the application uses SWRevealViewController https://github.com/John-Lluch/SWRevealViewController doesn't directly affect the problem that I have. If you are not familiar with this code base, just think of a Simple Bar Button that is shown at all times.
Now to the problem:
The Bar button that I want to show is associated with a few lines of code. (A property declaration and some methods).
This code should be used on a major part of the different view controllers in the application.
Now in the normal case, I'd just subclass UIViewController and make it the superclass of all my views that should show this button. However, my application should also show other types of views, such as a UITableViewController, so subclassing doesn't solve the entire problem.
If Objective-C supported Multiple Inheritance, I would make a class containing this code and let my other classes extend any subclass of UIViewController and my ugly support class at the same time.
Notes:
For now, my app is based on Storyboards
The TabBarController points to a number of UINavigationControllers, and not to any views that doesn't have a Navigation Bar.
I have tried implementing this with Objective-c Category where I add a category to UIViewController that does setup of my UIViewController. But I got stuck on this solution when I needed to add a #Property for the button and linking it to the XIB/Storyboard. Got the idea from this post Add the same UIBarButtonItem to several UIViewControllers but it doesn't contain any details.
tl;dr: I want to show the very same UIBarButtonItem on many of my applications views. The UIBarButtonItem is associated with some code, that is also the same for all these views.
What would be a good way to achieve this?
If i understood you correctly.
You want to show button for all your UIViewControllers.
There are many ways to achieve this. Please try this one.
1. Create a subclass of UIView with its XIB. It contains your button. create Properties and IBAction.
2. Implement your action on this subclass.
3. On .m file write the below code
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
if (![self.subviews count])
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSArray *loadedViews = [mainBundle loadNibNamed:#"MyView" owner:nil options:nil];
return [loadedViews firstObject];
}
return self;
}
where, MyView is the name of your view.
4. Drag and drop a UIViewand place it on every `UIViewController XIB (or storyboard in your case) and set its custom class to "MyView" (or the name of your newly created class).
5. Run your project.
For reference: May i help you?
I have now solved this problem and I will post it here for reference:
This solves the problem with adding a sidebar button to several views in the project, but the code should be usable for any UIBarButton. The solution is the create a Category for UIViewController that specifies a setup method. This setup method is called from the different Views.
Category .h file:
#import <UIKit/UIKit.h>
#interface UIViewController (SidebarCompliance)
- (void)setupSidebar;
#end
Category .m file:
#import "UIViewController+SidebarCompliance.h"
#import "SWRevealViewController.h"
#implementation UIViewController (SidebarCompliance)
- (void)setupSidebar {
SWRevealViewController *revealViewController = self.revealViewController;
if (revealViewController) {
UIBarButtonItem *sidebarButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menu.png"] landscapeImagePhone:[UIImage imageNamed:#"menu.png"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(revealToggle:)];
self.navigationItem.rightBarButtonItem = sidebarButton;
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
#end
And then an example of one of my views:
View .h file:
#import <UIKit/UIKit.h>
#import "UIViewController+SidebarCompliance.h"
#interface NumeroUno : UIViewController
#end
View .m file:
#import "NumeroUno.h"
#implementation NumeroUno
- (void)viewDidLoad {
[super viewDidLoad];
[self setupSidebar];
}
#end
I have a storyboard driven iOS application.
My objective is to add a small square view (defined as other XIB) to another UIView which is on main ViewController.
*// Please note that, I have assigned the Class names in Identity Inspector correctly*
On the main ViewController, I added a UIView (myHolderView) manually and added a UIView member in the ViewController interface.
//.h
#interface ViewController : UIViewController
#property(nonatomic, strong) IBOutlet UIView *myHolderView;
#end
And, I have connected this IBOutlet by "BlueString" :)
Now, I have added another XIB with single view - Called it MySquare.xib and added a label on it.
And, added a UIView class with a .h and .m files. And, "BlueString" connections are made.
#interface MySquare : UIView
#property(nonatomic, strong) IBOutlet UILabel *myLabel;
#end
Now, in the implementation:
#implementation ViewController
#synthesize myHolderView;
- (void)viewDidLoad
{
[super viewDidLoad];
MySquare *sq=[[MySqure alloc]init];
// Do any additional setup after loading the view, typically from a nib.
[self.myHolderView addSubview:sq];
}
When I run it in the simulator, it just shows the main view, but on it the square view is not coming.
I know that main view had loaded because... I changed the colour of it so that I could see.
Please help.
Probably you don't do in your MySquare.m file the view initialisation using your xib.
- (id) initWithFrame:(CGRect)frame {
NSLog(#"This is called if you add programatically this view");
self = [super initWithFrame:frame];
if (self) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"MyIBView" owner:self options:nil] objectAtIndex:0]];
}
return self;
}
If you plan to add your xib using Interface Builder, you have to implement similarly the initWithCoder method:
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"MyIBView" owner:self options:nil] objectAtIndex:0]];
}
return self;
}
Plese go through in this checklist, it might help others too:
Checklist adding a custom view with Interface Builder layout (xib):
1) create a new xib (File->New->IOS/User Interface->View), name it (eg. MyIBView)
2) create a new class (File->New->IOS/Cocoa Touch->Objective-C class), make sure it is a Subclass of UIView! Name it MyIBView.
Now you have MyIBView.xib, MyIBView.h and MyIBView.m files added to your project
3) Edit your MyIBView.xib: select the File's owner and using the Identity inspector (3rd icon) select Class you created recently, MyIBView.
4) Select the top level View (if its a new xib, only this exists) and make sure using the Identity inspector that the Class is UIView (grey) and not overwritten
5) Now you can add IBOutlets and/or IBActions to your MyIBView.h file and you can do connections using Interface Builder in your MyIBView.xib
Using this view programatically in another view:
6a) Create the first method (initWithFrame) above in your MyIBView.m file if you would like to use this custom view programatically
7a) include your MyIBView.h file where you would like to add your custom view programatically
8a) now you can add your view:
MyIBView *myIBView = [[MyIBView alloc] initWithFrame:CGRectMake(0,0,100,100)];
Using this view in Interface Builder in another view:
6b) Create the second method (initWithCoder) above in your MyIBView.m file if you would like to use this custom view in Interface Builder
7b) In your another view drop an UIView to your view canvas. Adjust the size and modify the Class using the Identity inspector to MyIBView.
Please note that you cannot see design time your custom view, only after trying to run the code.
Hope it helps, and you can find your miss-configuration!
This is another "I'm confused question". So I'm working on bringing in custom views into a view controller. I'll just outline the exact steps for the error.
Create a Single View Application Project
Create a Nib File via File -> New -> User Interface -> View; call it theNIB.xib. Add a simple label to make sure loading.
add following code:
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"theNIB" owner:self options:nil] objectAtIndex:0];
view.frame=CGRectMake(10.0f,10.0f,100.0f,100.0f);
view.backgroundColor=[UIColor orangeColor];
[self.view addSubview:view];
This works.
Now what I want to do is connect this nib with a UICustomView so I create ArcView via File -> New -> UIView.
'4. In IB, I need to connect theNIB to ArcView so I highlight the File's Owner in the Placeholders and select AcrView in the Custom Class.
'5.' Then I select the main View and set it to ArcView in the Custom Class.
I am at a loss for what the next step is or whether 4 or 5 were necessary (both / neither)? Do I try to make an outlet reference in ArcView to view for the main View in Interface Builder? Should I be able to Alt-drag from the View to the header file in assistant editor (I am not currently able to)?
thx in advance
** edit 1 **
Here's the File's Owner with arcView set:
View object with arcView not set:
Define an IBOutlet #property in your parent class's #interface section like this:
#property (weak, nonatomic) IBOutlet ArcView *arcView
Then go into Interface Builder, and right click on File's Owner. When you see "arcView" in the black HUD window, drag the mouse from that item to your view on the XIB.
Now you have a property for your arcview control, and you can utilize it just like you would any control such as UIButton, UILabel etc.
Set the file's owner == your UIView subclass so that you can connect outlets to it. And you should set the class of nib-painted UIView to that same subclass because it's an instance of that UIView subclass.
In other words, follow these steps:
create a UIView subclass called CustomView
create a UIView xib New File -> User Interface -> View
change the file's owner to CustomView
change the view's class to CustomView
add subviews if you wish, connect them as outlets to the files owner (CustomView)
Your crash is happening because your code says this:
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"theNIB" owner:self options:nil] objectAtIndex:0];
But that owner:self is the view controller where this code is running. You want the view subclass to be the nib's owner.
To fix, give your UIView subclass the job of init-ing itself from the nib, like this:
CustomView.h
#interface CustomView : UIView
- (id)initFromNib;
#end
CustomView.m
#import "CustomView.h"
#interface CustomView ()
// connect this in the XIB to file's owner that you've set to this CustomView class
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
#implementation CustomView
- (id)initFromNib
{
self = [[[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil] objectAtIndex:0];
if (self) {
// prove you can set properties on your outlets
self.myLabel.text = #"this is good";
}
return self;
}
I built a little project with just this stuff in it as described. Works fine. Lemme know if you'd like to see it and I'll find a way to send you an anonymous zip.
I am stuck at a simple task, I have uilabel on my uiviewcontroller's interface file. I want to update that label via some methods. It doesn't update the label.
.h
UIViewController
{
UILabel *pictureNameLabel;
}
#property (nonatomic, strong) IBOutlet UILabel *pictureNameLabel;
.m
#synthesize pictureNameLabel=_pictureNameLabel;
- (void)viewDidLoad
{
_pictureNameLabel = [[UILabel alloc] init];
_pictureNameLabel.textColor=[UIColor blackColor];
_pictureNameLabel.text=#"Try";
}
How can I fix that issue?
You don't need to alloc the label. It's already alive and get's awaken from the nib.
.h
UIViewController
{
//UILabel *pictureNameLabel;
}
#property (nonatomic, strong) IBOutlet UILabel *pictureNameLabel;
.m
#synthesize pictureNameLabel=_pictureNameLabel;
- (void)viewDidLoad
{
//_pictureNameLabel = [[UILabel alloc] init];
_pictureNameLabel.textColor=[UIColor blackColor];
_pictureNameLabel.text=#"Try";
}
Your direct problem is the line:
_pictureNameLabel = [[UILabel alloc] init];
In -ViewDidLoad. It's creating a new variable, and having the pictureNameLabel property point to it, causing you to lose your reference to the one created in Interface Builder. Remove that line, and everything should work fine.
If you've created an element via Interface Builder, you do not need to alloc & init it yourself, along with adding it to the view in the appropriate spot, as it's automatically done for you, and the property is already set to point to it. If you're manually creating a new view, you do need to do that... but you'd also need to add it somewhere in the view hierarchy as a subview.
Not related to your problem, but you have also created a variable named UILabel *pictureNameLabel;. I'd assume you created this variable to be the backing variable for the synthesized property pictureNameLabel... but, you synthesized that to _pictureNameLabel, which means you now have two variables, _pictureNameLabel and pictureNameLabel. This is almost certainly a mistake. You should either remove the manual definition of pictureNameLabel, or rename it to something distinct if you actually intend to use it separately from the property with the same name. Having it is likely to just lead to confusion & bugs down the road.
your label has already exists on your xib file, and you can set the textcolor, text on interface bulider.
I am new to IOS, Xcode and MVC. I am on a steep learning curve and am failing with what I assume is a most basic task.
I have a tabbed application with two tabs. Both tab views communicate with a web service and I want to add an image to each tab view, changing the image to indicate the connection state.
So, I created a third .xib file with a controller class (IconViewController). I am hoping to add and remove an instance of this icon view in each of the tab views.
Here is the pseudo code for my icon view:
#interface IconViewController : UIViewController
{
UIImageView *_icon;
}
#property (nonatomic) IBOutlet UIImageView *icon;
- (void)setForBusy;
- (void)setForOk;
- (void)setForFail;
And implementation:
#implementation IconViewController
#synthesize icon = _icon;
-(void)setForBusy
{
// Set Busy Icon Image
}
-(void)setForOk
{
// Set Ok Icon Image
}
-(void)setForFail
{
// Set Fail Icon Image
}
The icon IBOutlet is connected to an UIImageView on the accompanying xib file.
Here is one of the root tab controllers:
#import "IconViewController.h"
#interface TaboneViewController : UIViewController
{
IconViewController *_iconViewController;
}
#property (nonatomic) IBOutlet IconViewController *iconViewController;
and implementation:
#synthesize iconViewController = _iconViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
self.iconViewController = [[IconViewController alloc]
initWithNibName:#"iconViewController"
bundle:nil];
[self.view addSubview:self.iconViewController.view];
}
In the tabView xib Interface Builder I added an Object and made it a class type IconViewController. I connected the Icon View Controller Object->Reference Outlet to the File Owner->iconViewController Outlet.
Running the project I get the error:
loaded the "iconViewController" nib but the view outlet was not set.
I have experimented with other connections but with no luck. It seems to me that my first connection should work but it doesn't.
Any idea what I am misunderstanding? Is the principle good (loading an instance of third view into two root views)? If so, what outlet needs connecting?
Many thanks, Polly
I see your issue. You want to have common stage of image for both tab. I think it is better to implement subclass of UIView (or UIImageView) and implement all methods like set (void)setForBusy and etc. The stage of image you should receive from parent ViewController, something like UINavigationView controller (if you have it). Otherwise you should save stage somewhere else. My personal opinion it is too expensive to create new controller just for your purpose.
Hope it helps.