Creating Second uiview without IB or Xcode [closed] - ios

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Would someone be so kind as to point out where this tutorial is steering me wrong?
Open up the -SECOND- project you made and change the name of:
RootViewController.h
RootViewController.mm
To:
SecondView.h
SecondView.mm
Now, open up SecondView.h and change the following code:
#interface RootViewController: UIViewController {
}
#end
To:
#interface SecondView: UIViewController {
}
#end
Save and close SecondView.h and open up SecondView.mm. In SecondView.mm, let's change the following code:
#import "RootViewController.h"
To:
#import "SecondView.h"
And change the following code:
#implementation RootViewController
To:
#implementation SecondView
Part 2: Set up the view controller
Save and close SecondView.mm. In iFile, cut both SecondView.h and SecondView.mm and paste them into the testview project folder. Open your Makefile, and on the line:
testview_FILES = main.m testviewApplication.mm
Edit that line to look like:
testview_FILES = main.m testviewApplication.mm SecondView.mm
This will compile SecondView.mm into an object file (SecondView.o) and add it to the finalized testview binary (testview.app > testview). And guess what? That's how you set up a new class for your projects! Proceed to part 3!
Part 3: Set it up in-app (Usage)
So you have a new UIViewController and UIView ready to be used whenever you want huh? Well now we will call our view controller to present our amazingness view! With the shiny code:
//Bring SecondView to memory (RAM)
SecondView *second= [[[SecondView alloc] init] autorelease];
//Properties for second (SecondView)
second.title = #"UINavigationBar";
//Present second (SecondView) to user
[self presentModalViewController:second animated:YES];
Now that you have the ability to bring another view up front, a question you want to ask yourself is whether or not you want the user to be able to go back to the RootViewController. If not, then just skip this step. Using the action property of either UIButtons or UIBarButtonItems to UIAlertViews or UIActionSheets, you can call this whenever needed.
The problem is that my build is throwing an error of "SecondView was not declared in this scope" and "second was not declared here". Every other part of this tutorial has worked perfectly so I am assuming there's a typo here in Step 3 just above the code. I'm just jumping into apps developing and do not have the luxury of Xcode or many tutorials without Xcode. EVERYTHING HAS BEEN FOLLOWED TO THE LETTER. Thanks.

In your RootViewController.mm file
#import "RootViewController.h"
#import <UIKit/UIKit.h>
#import "SecondView.h"
#implementation RootViewController
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
self.view.backgroundColor = [UIColor redColor];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(21, 80, 100, 35);
[myButton setTitle:#"My Button" forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(myButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:myButton];
}
- (void)myButtonPressed {
SecondView *second= [[[SecondView alloc] init] autorelease];
second.title = #"UINavigationBar";
[self presentModalViewController:second animated:YES];
}
#end

Related

property frame not found on object of type _strong id

It is my first app that I am trying to build in IOS and I have some problems. Although I have read similar threads here I was not able to find the answer.I want to show popoverview controller on my button click.but unable to do. i am getting error mention in question title above below are my files
.h file
#property (nonatomic,strong) UIPopoverController *popOver;
#property (nonatomic,strong) SecondViewController *popOverView;
.m file
- (IBAction)Getcompany:(id)sender {
SecondViewController *popoverview=[self.storyboard instantiateViewControllerWithIdentifier:#"popover"];
self.popOver =[[UIPopoverController alloc] initWithContentViewController:popoverview];
[self.popOver presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];// m getting an error in this line
}
Thanx in advance.
You need to tell the compiler that sender is, in fact, a UIButton:
- (IBAction)Getcompany:(id)sender {
UIButton *button = (UIButton *)sender;
SecondViewController *popoverview=[self.storyboard instantiateViewControllerWithIdentifier:#"popover"];
self.popOver =[[UIPopoverController alloc] initWithContentViewController:popoverview];
[self.popOver presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
}
-or-
you can use the form:
[sender frame]
rather than:
sender.frame
NOTE: the name Getcompany is not conventional for an Objective-C method; I don't know what it does, but if it's an action method, then something like this is probably better:
- (IBAction)companyButtonPressed:(id)sender
(note lowercase starting letter and camel-case formatting).

Calling method from another class doesn't work properly

I am trying to change the text and the position of a UILabel from another class.
I have successfully managed to call my -changeLabel method, which is in my FirstViewController class, from my SecondViewController class. Here is the code I have used in my two classes:
SecondViewController:
#import "FirstViewController.h"
#interface SecondViewController ()
#property (nonatomic,strong) FirstViewController *firstViewController;
#end
#implementation SecondViewController
#synthesize firstViewController;
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
FirstViewController:
- (void)changeLabel {
NSLog(#"changeLabel is called!");
label.text = #"New text.";
label.frame = CGRectMake(10, 100, 150, 40);
NSLog(#"%#", label.text);
NSLog(#"%f", label.frame.size.width);
}
The weird thing is that the logger looks like this after pressing the "button" that calls the method:
"2013-12-30 19:24:50.303 MyApp[655:70b] changeLabel is called!"
"2013-12-30 19:24:50.305 MyApp[655:70b] New text."
"2013-12-30 19:24:50.308 MyApp[655:70b] 0.000000"
So it seems the label text change, but it doesn't show up on the screen. And the label width is logged as 0.0.. even though I just set it to 150.
Why is this happening? Am I not able to change frame variables from another class? Is there another way to do this?
IMPORTANT:
As the FirstViewController is the main view controller while the SecondViewController is a side menu, similar to the facebook app:
I want to be able to press a "button" on the SecondViewController(side menu) and call a method in the FirstViewController(main) that changes the position(frame) of a UILabel.
EDIT:
Here is how I created the UILabel:
label = [[UILabel alloc] init];
label.frame = CGRectMake(0, 0, 150, 40);
label.text = #"Text."
[self.view addSubview:label];
I think problem is this. You are calling method from new instance of FirstViewController.
Let assume
1. FirstViewController at stack[0].
2. SecondViewController at stack[1].
If you are navigating or moving from
FirstViewController->SecondViewController
In this case FirstViewController already in memory with some address 0x23ffff.
And in SecondViewController you are again creating new instance of FirstViewController which is point to another address '0x234jurhu`
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
Don't create new instance here.
You can use delegate or NSNotification concept for this.
How are you displaying FirstViewController?
Here is the issue:
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
You creating a new instance of FirstViewController and updating the label text. If your using these VC's in a navigation stack and you pop back to FirstViewController from SecondViewController, you won't see any label change because they are different instances of the class.
If your using FirstViewController as a childViewController of SecondViewController (with naming of them I don't think this what your doing), then in the - (IBAction)button:(id)sender method you don't need to instantiate a new instance of FirstViewController on each button press.
I have figured out a way to do this thanks to "#Gaurav Wadhwani" answer on this question: call method from other class (self issue).
I added this code in my FirstViewController.h:
+ (FirstViewController *)singletonInstance;
And then added this code in my FirstViewController.m
static FirstViewController *_singletonInstance = nil;
+(FirstViewController*)singletonInstance
{
#synchronized([FirstViewController class])
{
if (!_singletonInstance)
_singletonInstance = [[self alloc] init];
return _singletonInstance;
}
return nil;
}
+(id)alloc
{
#synchronized([FirstViewController class])
{
NSAssert(_singletonInstance == nil, #"Attempted to allocate a second instance of a singleton.");
_singletonInstance = [super alloc];
return _singletonInstance;
}
return nil;
}
Then I added this code in my SecondViewController to run the changeLabel method:
[[FirstViewController singletonInstance] changeLabel];
And that seems to work just fine so far. I hope it wont cause any other "problems" in the future, but right now it seems to be perfect.
Try doing this:
[label setNeedsDisplay];
After the last line in changeLabel.

iOS5 Assign a .xib to a custom UIView class

HI have a custom view class that is loaded and placed within my main view using the following code. The reason it that i want to populate it with different content so rather than build a view in code each time if I create a custom class i can reuse this in a loop etc, I got this to work just fine in code, that is laying out the buttons label etc.
But rather than hand code it all I thought if i create a new User Interface View, then construct visually my text fields, labels and buttons on this view.
Then connect it to my custom class.
Bu this is where I am having an issue, how do I connect this view xib file so that it becomes visible when placed on my my code. I have assigned the custom class attribute within the xib file to my custom file, but what else am i missing?
.h File:
#import <UIKit/UIKit.h>
#interface blogView : UIView
#end
.m File:
#import "blogView.h"
#implementation blogView
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
if (self != nil)
{
NSLog(#"Blog View loaded");
self.backgroundColor = [UIColor yellowColor];
UILabel *titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 400, 40)];
[titleLbl setText:#"This is the Title"];
[self addSubview:titleLbl];
}
return self;
}
#end
my xib file has the same name blogView.xib which is a View User Interface.
Within my main view controller and in the ViewDidLoad i have
blogView *blogItem = [[blogView alloc]init];
[self.view addSubview:blogItem];
When I run this is all works fine, but I would like to link to a .xib file to save time etc.
Thanks
Well having look around and trying bits of clues and suggestion I managed to do this with the following:
Within my .m file I placed/Changed the following:
self = [super init];
if (self != nil)
{
NSArray *theView = [[NSBundle mainBundle] loadNibNamed:#"blogView" owner:self options:nil];
UIView *nv = [theView objectAtIndex:0];
.. rest of code.
[self addSubview:nv];
.. rest of code.
Many Thanks
I struggled with this for an hour when I RENAMED my viewcontroller class. This is what worked for me in Xcode 5
Go to your XIB file
Click on Files owner transparent box on the left
Open up your inspections tab(Third button on right in the View Section - in between Editor and Organizer)
Go to your identity Inspector(3rd from the left) underneath the editor organizer view tab.
Fix the custom class - Class option to whatever class you want it to respond to.
Lets just say I was extremely annoyed after wasting time with that
You might want to create a controller for your view and load that view using initWithNibName:bundle:

iOS - passing Sender (button) name to addSubview

I have a main view with 3 buttons. Clicking on any of the buttons adds a SubView.
The buttons have different titles and are all linked to IBAction "switchView"
The "switchView" code is below.
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
[self.view addSubview:myViewController.view];
}
The "secondView" loads up correctly and everything works well.
The problem is I want to be able to know which button was the Sender.
I don't want to create 3 subviews, one for each button. The code and XIB would be absolutely the same>
The only difference would be a variable that I would like to set up in the second view (viewDidLoad method) depending on who is the Sender (which button was clicked)
Is this possible? Or I would need to create 3 subViews - one for each button?
Your help is greatly appreciated!
You can identify different buttons with the tag property.
e.g. with your method:
-(IBAction)switchView:(id)sender {
UIButton *button = (UIButton*)sender;
if (button.tag == 1) {
//TODO: Code here...
} else if (button.tag == 2) {
//TODO: Code here...
} else {
//TODO: Code here...
}
}
The tag property can be set via the InterfaceBuilder.
Hope this helps.
I think you can solve in 2 ways:
Create a property like:
#property (nonatomic, strong) IBOutlet UIButton *button1, *button2, *button3;
in your viewcontroller and link the buttons to them as referencing outlet on the XIB.
Give a different tag to each button on your xib and ask for the tag of the sender with UIButton *b=(UIButton*)sender; b.tag; like Markus posted in detail.
Solving my problem it all came down to transferring data between the mainView and subView.
In my mainView.h I declared an NSString and its #property
...
NSString *btnPressed;
}
#property(nonatomic, retain) NSString *btnPressed;
...
then in my mainView.m inside the switchView method I did this:
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
btnPressed = [NSString stringWithFormat:#"%i", [sender tag]];
[myViewController setBtnPressed:self.btnPressed];
[self.view addSubview:myViewController.view];
}
This line in the code above actually takes care of transferring the data to the newly created subView:
[myViewController setBtnPressed:self.btnPressed];
Then in my secondView.h I declare exactly the same NSString *btnPressed and its #property (though this a completely different object than the one declared in main)
Then in my secondView.m I get the value of the button pressed I'm interested in.
- (void)viewDidLoad {
[super viewDidLoad];
int theValueOfTheButtonPressed = [self.btnPressed intValue];
}
This works well.
Don't forget to #synthesize btnPressed; as well as [btnPressed release]; in both mainView.m and secondView.m

UIView and UIViewController

I know this is really basic stuff but i need to understand whether my understanding of this is correct.
So what i want to do is this. I want an view with a label on which when double tapped flips and loads another view. On the second view i want a UIPickerView and above i have a button saying back. Both views will be of same size as an UIPickerView which is 320px x 216px.
What i am thinking of to do is create two UIViewclasses named labelView and pickerView. I would then create a viewController which on loadView loads labelView then when user double taps the labelView i get an event in labelView class which is sent to my viewController that then can unload loadView and load the pickerView.
Does this sound as the best way to do this ? Is there a simpler way ? I am also unsure how i route the event from the labelView class to the viewControllerclass.
I dont exactly know the most efficient way to do it(as i am also now to this language),but it is for sure that i have solved ur problem. I made a simple program for that.Three classes involved here in my eg are BaseViewController (which will show two views),LabelView and PickerView (according to ur requirement).
In LabelView.h
#protocol LabelViewDelegate
-(void)didTapTwiceLabelView;
#end
#interface LabelView : UIView {
id <LabelViewDelegate> delegate;
}
#property(nonatomic,retain)id <LabelViewDelegate> delegate;
-(void)didTouch;
#end
In LabelView.m
#synthesize delegate;
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self)
{
UILabel* labl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, frame.size.width-20,20)];
labl.text = #"Some Text";
[self addSubview:labl];
[labl release]; labl = nil;
self.backgroundColor = [UIColor grayColor];
UITapGestureRecognizer* ges = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTouch)] autorelease];
ges.numberOfTapsRequired = 2;
[self addGestureRecognizer:ges];
}
return self;
}
-(void)didTouch
{
[delegate didTapTwiceLabelView];
}
//=============================================================
In Pickerview.h
#protocol PickerViewDelegate
-(void)didTapBackButton;
#end
#interface PickerView : UIView <UIPickerViewDelegate,UIPickerViewDataSource>{
id <PickerViewDelegate> delegate;
}
#property(nonatomic,retain)id <PickerViewDelegate> delegate;
#end
In Pickerview.m
#implementation PickerView
#synthesize delegate;
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self)
{
UIPickerView* picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 30, 320, 216)];
picker.delegate = self;
picker.dataSource = self;
[self addSubview:picker];
[picker release]; picker = nil;
self.frame = CGRectMake(frame.origin.x, frame.origin.y, 320, 250);
UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(10, 1, 50, 27)];
[btn setTitle:#"Back" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(backButton) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:btn];
}
return self;
}
-(void)backButton
{
[delegate didTapBackButton];
}
//====================================================================
in BaseViewController.h
#import "LabelView.h"
#import "PickerView.h"
#interface VarticalLabel : UIViewController<UITextFieldDelegate,PickerViewDelegate,LabelViewDelegate> {
PickerView* myPickerView;
LabelView* myLabelView;
}
#end
In BaseViewController.m
-(void)viewDidLoad
{
[super viewDidLoad];
myPickerView= [[PickerView alloc] initWithFrame:CGRectMake(0, 50, 320, 250)];
[self.view addSubview:myPickerView];
myPickerView.delegate = self;
myLabelView= [[LabelView alloc] initWithFrame:CGRectMake(0, 50, 320, 250)];
[self.view addSubview:myLabelView];
myLabelView.delegate = self;
myPickerView.hidden = YES;
}
#pragma mark PickerViewDelgate
-(void)didTapBackButton
{
myPickerView.hidden = YES;
myLabelView.hidden = NO;
}
#pragma mark LabelViewDelegate
-(void)didTapTwiceLabelView
{
myPickerView.hidden = NO;
myLabelView.hidden = YES;
}
To get events from a button to the view controller, just hook up the button's event, e.g. touch up inside, to a method in the view controller, using interface builder. (Double tapping is probably more complicated though.)
When you say 'flips', do you mean it actually shows an animation of flipping over a view to show a 'reverse' side? Like in the weather app when you hit the 'i' button? I'm assuming this is what you mean.
Perhaps check TheElements sample example on the iPhone Reference Library, it has an example of flip animation.
Btw, it's not strictly necessary to unload the loadView that is being 'hidden' when you flip -- it saves you having to construct it again when you flip back -- but it may be pertinent if you have memory use concerns, and/or the system warns you about memory being low.
Also, what do you mean by "create a UIView"? Do you mean subclass UIView, or just instantiate a UIVIew and add children view objects to it? The latter is the usual strategy. Don't subclass UIView just because you want to add some things to a UIView.
If you've got one screen of information that gives way to another screen of information, you'd normally make them separate view controllers. So in your case you'd have one view controller with the label and upon receiving the input you want, you'd switch to the view controller composed of the UIPickerView and the button.
Supposing you use Interface Builder, you would probably have a top level XIB (which the normal project templates will have provided) that defines the app delegate and contains a reference to the initial view controller in a separate XIB (also supplied). In the separate XIB you'd probably want to add another view controller by reference (so, put it in, give it the class name but indicate that its description is contained in another file) and in that view controller put in the picker view and the button.
The point of loadView, as separate from the normal class init, is to facilitate naming and linking to an instance in one XIB while having the layout defined in another. View controllers are alloced and inited when something that has a reference to them is alloced and inited. But the view is only loaded when it is going to be presented, and may be unloaded and reloaded while the app is running (though not while it is showing). Generally speaking, views will be loaded when needed and unnecessary views will be unloaded upon a low memory warning. That's all automatic, even if you don't put anything in the XIBs and just create a view programmatically within loadView or as a result of viewDidLoad.
I've made that all sound more complicated than your solution, but it's actually simpler because of the amount you can do in Interface Builder, once you're past the curve of learning it. It may actually be worth jumping straight to the Xcode 4 beta, as it shakes things up quite a lot in this area and sites have reported that a gold master was seeded at one point, so is likely to become the official thing very soon.
With respect to catching the double tap, the easiest thing is a UITapGestureRecognizer (see here). You'd do something like:
// create a tap gesture recogniser, tell it to send events to this instance
// of this class, and to send them via the 'handleGesture:' message, which
// we'll implement below...
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleGesture:)];
// we want double taps
tapGestureRecognizer.numberOfTapsRequired = 2;
// attach the gesture recogniser to the view we want to catch taps on
[labelView addGestureRecognizer:tapGestureRecognizer];
// we have an owning reference to the recogniser but have now given it to
// the label. We don't intend to talk to it again without being prompted,
// so should relinquish ownership
[tapGestureRecognizer release];
/* ... elsewhere ... */
// the method we've nominated to receive gesture events
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
// could check 'gestureRecognizer' against tapGestureRecognizer above if
// we set the same message for multiple recognisers
// just make sure we're getting this because the gesture occurred
if(gestureRecognizer.state == UIGestureRecognizerStateRecognized)
{
// do something to present the other view
}
}
Gesture recognisers are available as of iOS 3.2 (which was for iPad only; so iOS 4.0 on iPhone and iPod Touch).

Resources