Here's the basic code (based on Xcode's Tabbed Applicaion Template)
ViewController.h
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic,retain) NSMutableArray *movies;
#property (nonatomic,retain) IBOutlet UITableView *tableView;
ViewController.m
#implementation ViewController
#synthesize movies,tableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Watchlist", #"Watchlist");
self.tabBarItem.image = [UIImage imageNamed:#"watchlist"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"tableView = %#", tableView);
}
Output
tableView = (null)
The TableView is connected to File's owner in IB with class is set to ViewController
I really don't get why the tableView is null.
I'm not a complete newbie to Cocoa (but to the iPhone SDK), I created a Single View based Application with a TableView dataSource to see if I was missing something. I got it working in under a minute.
Anybody can help out?
In interface builder right click File's Owner and ensure that the following connections are made:
Outlets
tableView - Table View
Referencing Outlets
dateSource - Table View
delegate - Table View
I suspect you may have not made the first connection?
Make sure the nib/xib is included in your current target.
I just experienced this issue on Xcode5 with iOS7 SDK. Strangely enough, I discovered that the nib wasn't included in my target anymore. I don't know when and why that happened, but it had this strange side effect that most IBOutlets weren't set up properly, even if all connections from code to nib/xib were fine.
For example: my MKMapView *map was in my list of subviews on viewDidLoad:, but the IBOutlet MKMapView *map property in my view controller was still nil. After I ticked the "include in target" checkbox, everything worked as expected.
Related
I've been working on putting together a simple program that will display user information in an MVC model. The application works perfectly when all the data is on the View Controller, however, when attempting to move the data to a Profile model, the application will successfully build, however, no information will show up. Here is the code that I'm working with right now.
The Profile View Controller header:
DefaultProfileViewController.h
#import <UIKit/UIKit.h>
#import "Profile.h"
#interface DefaultProfileViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *fullNameLabel;
#property (nonatomic, strong) Profile *profile;
#end
The Profile View Controller Implementation
#import "DefaultProfileViewController.h"
#class Profile;
#interface DefaultProfileViewController ()
#end
#implementation DefaultProfileViewController
#synthesize profile = _profile;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_fullNameLabel.text = _profile.fullName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The Profile model header
#import <Foundation/Foundation.h>
#interface Profile : NSObject
#property (nonatomic, copy) NSString *fullName;
- (void)loadProfile:(NSString *)fullName;
#end
And the Profile model implementation
#import "Profile.h"
#implementation Profile
#synthesize fullName = _fullName;
- (void)loadProfile:(NSString *)fullName
{
_fullName = #"Full Name";
}
#end
As mentioned earlier, if the _fullName = #"Full Name" portion is used in the controller, this works no problem, and the text Full Name will display in the simulator. If the Profile model is used, the application will build, no errors or warnings, yet no information is displayed. I'm sure I'm overlooking something extremely simple, so any help would be greatly appreciated. Thanks.
You code sample declares the property profile but nowhere do you actually set the profile.
Remember that declared properties in Objective-C 2.0 do one thing - which is to create the accessor methods for you "behind your back." (In the "old days" we had to write accessor methods by hand. Laborious; but you got very good at memory management!)
In your case, likely whatever class that instantiates DefaultProfileViewController needs to create a Profile object and the call setProfile on the new DefaultProfileViewController instance.
Something like this:
// create Profile object
Profile *aProfile = [[Profile alloc] init];
[aProfile loadProfile:#"John Doe"];
DefaultProfileViewController *vc = [[DefaultProfileViewController alloc] initWithNibName:#"your nib name" bundle:nil];
// set the profile on your view controller
vc.profile = aProfile;
// add your view controller's view to the view hierarchy
// however you are doing that now...
Note, assumes ARC.
My problem is that in ProductNote class UIButton Action I did initWithNibName Notes Class to show the popOver with a UITableView in Notes Class. I am fetching data from sqlite and then load it to UITableView in tableViewDidSelectRowAtindexPath:. I got the selectedNote and creates object of ProductNote Class to call selectedNote instance method that only set IBOutlet's textview.text but its nil. Thats my problem, Below is the code please help me to knowing why i face this type of issue. I am using Xcode 4.3.3 and not using ARC. Manually I defined dealloc method on every ViewController
//**ProductNote.h Class****************************
#import <UIKit/UIKit.h>
#class Notes;
#interface ProductNote : UIViewController<UIPopoverControllerDelegate>
{
UIPopoverController *popOverController;
UITextView *txtmesssagenotes;
Notes *objNotes;
}
#property (retain, nonatomic) IBOutlet UITextView *txtmesssagenotes; //It is Connected to ProductNote.xib
#property (retain,nonatomic) UIPopoverController *popOverController;
#property (retain,nonatomic) Notes *objNotes;
-(IBAction)presentPopOver:(UIButton*)sender;
-(void)selectedNote:(NSString*)note;
#end
//ProductNote.m Class
#implementation ProductNote
#synthesize txtmesssagenotes,popOverController,objNotes;
-(IBAction)presentPopOver:(UIButton*)sender
{
self.objNotes=[[Notes alloc]initWithNibName:#"Notes"bundle:nil];
UIPopoverController *popOver=[[[UIPopoverController alloc]initWithContentViewController:objNotes]autorelease];
self.popOverController=popOver;
self.popOverController.delegate=self;
self.popOverController.popoverContentSize=objNotes.view.frame.size;
CGRect rect=[self.view convertRect:objNotes.view.frame fromView:self.view];
rect.origin.y+=110;
rect.origin.x+=23;
[self.popOverController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:0 animated:YES];
//Then I get popOver with tableview
}
-(void)selectedNote:(NSString*)note
{
self.txtmesssagenotes.text=note;
//Here I am getting txtmesssagenotes=0X0 or nil. Using self or without self Please tell me the reason.
}
- (void)dealloc {
[txtmesssagenotes release];
[popOverController release];
[objNotes release];
[super dealloc];
}
#end
#interface Notes : UITableViewController
{
NSMutableArray *arrNotes;
NSString *selectedNote;
UITableView *tblNotes;
}
#property(nonatomic,retain)NSMutableArray *arrNotes;
#property(nonatomic,retain)NSString *selectedNote;
#property(nonatomic,retain)IBOutlet UITableView *tblNotes;
#end
//Actually I skip the other methods that makes larger program to read . other methods only used to fetch data from sqlite and fill up the arrNotes that is used to fill all rows in the tableview.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedNote=[self.arrNotes objectAtIndex:indexPath.row];
//Here self.arrNotes valid object and contains the data, and assigns NSString object to self.selectedNote
ProductNote *productNote=[[ProductNote alloc]init];
[productNote selectedNote:self.selectedNote]; //after calling selectedNote i goto to selectedNote implementation or definition above.
[productNote release];
}
-(void)dealloc
{
[arrNotes release];
[selectedNote release];
[tblNotes release];
[super dealloc];
}
It is because just as you stated that txtmesssagenotes was created using IB. And you never presented your ProductNote UIViewController instant productNote. So the txtmesssagenotes was never allocated and initialized properly.
Are you calling selectedNote: before your view has loaded?
Just because you created a view controller with a xib doesn't mean that it loads all your subviews immediately.
The xib is parsed and all your views are created the first time that the view controller's view property is asked for - this is usually just before it appears for the first time.
Until then, all the IBOutlet connections will be nil.
You need to store the text for your note as an NSString property of you view controller. Then, inside either viewDidLoad you need to call self.txtmesssagenotes.text=self.note; - viewDidLoad is automatically called just after your view is loaded so you are guaranteed to have all your IBOutlets set by then.
You shouldn't rely on your view objects to store the state of your app (in this case, the text of the note). If a low memory warning is received while your view controller isn't visible then all your view objects will be deleted - they will only be recreated when your view controller becomes visible again - if you are storing your note string inside a UITextView then it might no be there the next time you ask for it :) You should always store data in a property of your view controller (or somewhere else you control) and create your views using it.
I'm new on this, and I would like to get some advice because I don't know what I'm doing wrong.
I want to make an app in xcode, with a UIView with some items, and when you do something, another UIView (smaller than the first) pops up above the first UIView. The popup UIView would be a customized class.
I have started with the UIViewController template and the initial UIView, and I have linked all the items in the .storyboard, and it works. But when I create my own UIView class (from objective-C class), put the second UIView over the first in the storyboard and link it to my class, something goes wrong.
The UIView appears, but when I try to set it to hidden, it doesn't answer. It's like it's not receiving the messages, so I think I don't link it well programmatically and just appears because of the storyboard.
I don't know if I have to create another UIViewController instead of the UIView, or if this is the correct path.
Can anybody explain me a little, or just write a little code snippet with the instantiation of the second view and adding it?
Lots of thanks!!
(I paste some code, of the declaration in .h and instantiation in .m)
#import <UIKit/UIKit.h>
#import "EditView.h"
#interface ReleaseViewController : UIViewController <UIWebViewDelegate, UISearchBarDelegate> {
IBOutlet UIWebView *web;
IBOutlet UISearchBar *search;
IBOutlet EditView *evHack;
}
#property (nonatomic, retain) IBOutlet UIWebView *web;
#property (nonatomic, retain) IBOutlet UISearchBar *search;
#property (nonatomic, retain) IBOutlet EditView *evHack;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
search.delegate = self;
web.delegate = self;
evHack = [evHack initWithFrame:CGRectMake(0, 44, 320, 377)];
[evHack setHidden:YES];
}
EditView Class (I still have nothing):
#import <UIKit/UIKit.h>
#interface EditView : UIView
#end
#import "EditView.h"
#implementation EditView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"View created");
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
initWithFrame only works when you alloc/init an app. If its already initialized, in this case by the storyboard, just set its frame:
evHack.frame = CGRectMake(0,44, 320, 377);
I don't know what it looks like in IB, But setting its frame in code may be redundant if you set it in IB too. To check whether evHack is hooked up right, NSLog evHack in viewDidLoad. If you get nil back, it's not hooked up right.
I'm currently learning iPhone applications development, and I made some online tutorials to learn how all this is working.
I'm now quite used to the Objective-C concepts, and I'm trying to build a first application based on two views :
The first view would be the "Login view", simply with a kind of login system : a login field and a password field, and a "connect" button.
The second view is the "Home view" of the application, which will be called after the login.
I made a push segue to make the relation between the Login view and the view that is called after login. Here's what the storyboard looks like :
What I don't know actually is how to call a function that will check if the credentials are correct, and the switch to the other view if the login succeed.
Can anyone explain me, or give me some tips / tutorials for this please ?
Here are the sources for my LoginController :
LoginController.h
#interface LoginController : UIViewController {
IBOutlet UITextField *TFLogin;
IBOutlet UITextField *TFPassword;
}
#property (strong, nonatomic) IBOutlet UITextField *TFLogin;
#property (strong, nonatomic) IBOutlet UITextField *TFPassword;
- (IBAction)Connect:(UIButton *)sender;
#end
LoginController.m
#implementation LoginController
#synthesize TFLogin;
#synthesize TFPassword;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)Connect:(UIButton *)sender
{
if ([TFLogin.text isEqualToString:#"myLogin"] && [TFPassword.text isEqualToString:#"myPassword"]) {
[self performSegueWithIdentifier:#"LoginSegue" sender:sender];
NSLog(#"Connection OK");
}
else {
NSLog(#"Connection Not OK");
}
}
#end
Thanks !
You have two choices for triggering a segue. The easy way is just to ctrl-drag in interface builder from the button to the next view controller. You can also do it in code (in an IBAction), by calling performSegueWithIdentifier:sender:.
If you go with the IBAction, you can validate the data there.
If you go with the interface builder method, you can't validate -- prepareForSegue:sender: will be too late. Anyway, there's a possible stumbling block here -- as I recall, UINavigationController doesn't forward prepareForSegue:sender: to its children. You can mitigate this with a category on UINavigationController or by subclassing.
I have a view with a UITextView and a button, both connected via an IBOutlet. Pressing the button brings up a ModalViewController. I need to pass the text in the UITextView to the ModalViewController as a string. I've done a bit of Googling but could only find info on passing strings from the ModalViewController to the parent view.
PS: Forgive my newbieness :p
Is the ModalViewController object created and presented in an IBAction method? If so, in that method you should query the UITextView for its value (textView.text) and pass it to the ModalViewController.
You could subclass init with nib:bundle to include a string for the mycontroller view controller. So that in it's .h you will have
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andstring:(NSString *)string;
and in the viewcontroller's .m you will have
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andstring:(NSString *)string
{
//initialize self here from bundle;
//do other stuff
self.text=string}
assuming you define a NSString *text propery in the header of the view controller which you present modally;
Then in where you define my controller you would do
MYVCController *mycontroller=[[MYVCController alloc] initWithNibName:nibname bundle:bundlename andstring:textView.text];
Either you need to create a property for setting a variable inside the modal view controller, or you can define a method and do that.
e.g.
#interface ModalViewController : UIViewController {
NSString *displaystr;
}
#property (nonatomic, retain) NSString *displaystr;
...
#end
#implementation ModalViewController
#synthesize displaystr;
...
#end
Then you can use the property displaystr to store the text in the UITextField. You can get the text via the text property.
Make a NSString varible in appDelgate class and make it property.
NSString *value;
#property(nonatomic,retain) NSString *value;
and synthesize it in .m
#synthesize value;
Make object for you app delegate class and access that to set that value and get that value.
in modelViewController
write this code for button which you use to dismiss
yourAppDelegateClass *objDelegate=(yourAppDelegate *)[[UIApplication sharedApplication] delegate];
objDelegate.value=textView.text;
and by the object of app delegate you can access the value.