Objective C: Unable to Assign value to Labels - objective-c

I am trying to access properties of an object (person's firstName) which is stored in an array and assign it to labels in a seperate view Controller (SplitMethodViewController). The name value is successfully assigned here. Code snippet as below:
In the initial view controller (before displaying the modal view controller containing the UILabel):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = [indexPath row];
Person *thisPerson = (Person *)[self.personArray objectAtIndex:row];
SplitMethodViewController *smvc = [[SplitMethodViewController alloc]initWithNibName:nil bundle:nil];
smvc.nameLabel.text = [[NSString alloc] initWithFormat:#"%#", thisPerson.firstName];
//This lines returns the value I want, showing that assignment is working till this point
NSLog(#"The name label is %#", smvc.nameLabel.text);
[self presentModalViewController:smvc animated:YES];
[smvc release];
}
However, the values became blank when I check in the splitMethodViewController (checked in ViewDidLoad Method)
#interface SplitMethodViewController : UIViewController
{
UILabel *nameLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#end
#implementation SplitMethodViewController
#synthesize nameLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
self.nameLabel = [[UILabel alloc] init];
}
return self;
}
- (id)init
{
return [self initWithNibName:nil bundle:nil];
}
- (void)viewDidLoad
{
//name label returning nothing here.
NSLog(#"namelabel is %#",self.nameLabel.text);
[super viewDidLoad];
}
#end
I am sure I made some silly mistake somewhere. I have tried deleting all the outlets and labels and re-created just one name label and outlet. But I am still hitting this same issue.
Any help will be appreciated!

Did you actually allocate and instantiate the nameLabel and evenBillAmountLabel once you instantiate the SplitMethodViewController? In Objective-C messages (method calls) can be sent to nil (non-existant objects) without returning any errors, but also without any results.
Make sure the -init method on SplitMethodViewController looks somewhat like this:
// this is the designated initializer of most view controllers,
// do initialization here ...
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
{
self = [super initWithNibName:nibName bundle:nibBundle];
if (self)
{
nameLabel = [[UILabel alloc] init];
evenBillAmountLabel = [[UILabel alloc] init];
// add other stuff you need to initialize ...
}
return self;
}
- (id)init
{
// since we don't wanna re-implement allocation and instantiation for every
// initializer, we call the 'designated initializer' with some default values,
// in this case the default nibName and bundle are nil.
return [self initWithNibName:nil bundle:nil];
}
- (void)dealloc
{
[nameLabel release];
[evenBillAmountLabel release];
[super dealloc];
}
Be sure to read about designated initializers if this is new to you and if this was related to your issue. Here's a link to Apple's documentation on the subject.

If Wolfgang's answer doesn't solve it, be sure that your UILabel references in your SplitMethodViewController.xib file are wired up to the correct referencing outlet in your SplitMethodViewController.h file.

Related

TableView Delegate Messages Not Being Called

SOLVED: Not really a solution, but I just used a .xib rather than trying to use the storyboard thing. Whatever I was trying to do with the storyboard was somehow messing up the TableView delegate methods from being called. Thanks for all the insight you guys provided.
I have a UIViewController that contains a UITableView that should be populated by an array.
Unfortunately the UITableView does not get populated by the array (which is not empty).
My .h file:
#interface Directory : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate> {
NSArray *listData;
NSArray *savedListData;
MKMapView* mapUI;
UISearchBar* searchBar;
NSArray * originalListData;
UITableView* placeList;
DirInfoListing *infoInst;
NSString *searchInit;
NSString *openInit;
NSMutableArray *buildings;}
#property (nonatomic, retain) NSArray *listData;
#property (nonatomic, retain) NSArray *savedListData;
#property (nonatomic, retain) IBOutlet UISearchBar* searchBar;
#property (nonatomic, retain) IBOutlet UITableView* placeList;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list: (NSArray*)array mapView:(MKMapView*) map;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list:(NSArray*)array mapView:(MKMapView*) map search:(NSString*) ss;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil list: (NSArray*)array mapView:(MKMapView*) map open:(NSString*) openTx;
-(void)doDBLoad;
#end
And relevant stuff from my .m file:
#import "Directory.h"
#interface Directory ()
#end
#implementation Directory
#synthesize listData, savedListData;
#synthesize searchBar;
#synthesize placeList;
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"ListData count: %lu", (unsigned long)savedListData.count);
//This returns a valid number of 74 items
return [self.savedListData count];
}
/*
* Populates the table with list data and provides title. AND DOES NOT GET CALLED
*/
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *tID = #"tablIDDirect";
UITableViewCell *c = [tableView dequeueReusableCellWithIdentifier:tID];
if(c == nil) {
c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tID];
}
NSInteger r = [indexPath row];
if([self.listData objectAtIndex:r] != nil){
c.textLabel.text = ((DBBuilding*)[self.savedListData objectAtIndex:r]).Name;
c.detailTextLabel.text = ((DBBuilding*)[self.savedListData objectAtIndex:r]).Acronym;
}
c.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return c;
}
/*
* Displays an entry according to the table selection and redirects the user to the Directory Information Listing.
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger r = [indexPath row];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if(infoInst != nil) {
infoInst = nil;
}
infoInst = [[DirInfoListing alloc] initWithNibName:#"DirInfoListing" bundle:nil building:[self.savedListData objectAtIndex:r] map:mapUI];
}
/*
* Notification that the Directory is the active view
*/
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(openInit != nil)
{
[self openEntry:openInit];
openInit = nil;
}
placeList = [[UITableView alloc] init];
placeList.dataSource = self;
placeList.delegate = self;
[placeList reloadData];
}
/*
* Notification that the Directory is no longer the active view
*/
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (void)viewDidLoad
{
NSLog(#"ListData count: %lu", (unsigned long)listData.count);
//Also returns a valid number of 74 objects within the array
savedListData = [[NSArray alloc] initWithArray:listData];
//That get put into another array just for my sanity
[super viewDidLoad];
// Do any additional setup after loading the view.
searchBar.text = searchInit;
[self performSearch:searchInit];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionmethod gets called, but none of the other UITableView delegate methods are called and I am at a loss as to why this happens.
Also, this whole chunk of code is pulled from another one of my apps (That works correctly) using .xibs and DOES NOT use storyboards. This app (the one I'm having problems with) uses storyboards, which I am not very familiar with. I may be doing something wrong with calling and using the storyboard, but I am just not sure. If there may be something related to that I can provide more information.
Could you guys please go over my code and maybe see where I've gone wrong?
Thanks!
In your "viewDidLoad" method, change one line to this:
self.savedListData = [[NSArray alloc] initWithArray:listData];
Except "listData" needs to be something. "self.listData" might be that something, but on my first pass, I do not see where "self.listData" gets populated or set.
With properties, you usually use "self." to access (set and get) everything for the properties everywhere except in the init methods.
The reason the table is not displaying anything is because your "numberOfRowsInSection" method is likely returning zero. Set a breakpoint and check that.

why is this OCUnit test failing?

It's stepping into the ViewDidLoad of the main view controller, and hitting the line calling get all tweets, but I put a breakpoint in the getAllTweets of both the base and derived to see if it just wasn't hitting the derived like I expected.
#implementation WWMainViewControllerTests {
// system under test
WWMainViewController *viewController;
// dependencies
UITableView *tableViewForTests;
WWTweetServiceMock *tweetServiceMock;
}
- (void)setUp {
tweetServiceMock = [[WWTweetServiceMock alloc] init];
viewController = [[WWMainViewController alloc] init];
viewController.tweetService = tweetServiceMock;
tableViewForTests = [[UITableView alloc] init];
viewController.mainTableView = tableViewForTests;
tableViewForTests.dataSource = viewController;
tableViewForTests.delegate = viewController;
}
- (void)test_ViewLoadedShouldCallServiceLayer_GetAllTweets {
[viewController loadView];
STAssertTrue(tweetServiceMock.getAllTweetsCalled, #"Should call getAllTweets on tweetService dependency");
}
- (void)tearDown {
tableViewForTests = nil;
viewController = nil;
tweetServiceMock = nil;
}
The base tweet service:
#implementation WWTweetService {
NSMutableArray *tweetsToReturn;
}
- (id)init {
if (self = [super init]) {
tweetsToReturn = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the base of get all tweets");
return tweetsToReturn;
}
#end
The Mock tweet service:
#interface WWTweetServiceMock : WWTweetService
#property BOOL getAllTweetsCalled;
#end
#implementation WWTweetServiceMock
#synthesize getAllTweetsCalled;
- (id)init {
if (self = [super init]) {
getAllTweetsCalled = NO;
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the mock class.");
getAllTweetsCalled = YES;
return [NSArray array];
}
The main view controller under test:
#implementation WWMainViewController
#synthesize mainTableView = _mainTableView;
#synthesize tweetService;
NSArray *allTweets;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
allTweets = [tweetService getAllTweets];
NSLog(#"was here in view controller");
}
- (void)viewDidUnload
{
[self setMainTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
Since you're able to break in the debugger in viewDidLoad, what's the value of the tweetService ivar? If it's nil, the getAllTweets message will just be a no op. Maybe the ivar isn't being set properly or overridden somewhere else.
You should probably use the property to access the tweetService (call self.tweetService) rather than its underlying ivar. You should only ever access the ivar directly in getters, setters, and init (also dealloc if aren't using ARC for some crazy reason).
You also should not call loadView yourself, rather just access the view property of the view controller. That will kick off the loading process and call viewDidLoad.
Also, if you're doing a lot of mocking, I highly recommend OCMock.

Setup and send custom delegate method within init?

i have a question about initializing a custom delegate.
Within MyScrollView initWithFrame method, there is the first position where i need to send my delegate. But it´s still unknown there, because i set the delegate within MyCustomView after the initializer.
How can i fix that, so the delegate gets called even within init?
Thanks for your help..
MyCustomView.m
self.photoView = [[MyScrollView alloc] initWithFrame:frame withDictionary:mediaContentDict];
self.photoView.delegate = self;
//....
MyScrollView.h
#protocol MyScrollViewDelegate
-(void) methodName:(NSString*)text;
#end
#interface MyScrollView : UIView{
//...
__unsafe_unretained id <MyScrollViewDelegate> delegate;
}
#property(unsafe_unretained) id <MyScrollViewDelegate> delegate;
MyScrollView.m
-(id) initWithFrame:(CGRect)frame withDictionary:(NSDictionary*)dictionary{
self.content = [[Content alloc] initWithDictionary:dictionary];
self = [super initWithFrame:frame];
if (self) {
//.... other stuff
// currently don´t get called
[self.delegate methodName:#"Test delegate"];
}
return self;
}
I am sure you have defined a:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary;
Then, just pass the delegate, too:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary withDelegate:(id<MyScrollViewDelegate>)del;
In the Implementation File:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary withDelegate:(id<MyScrollViewDelegate>)del {
// your stuff...
self.delegate = del;
[self.delegate methodName:#"Test delegate"];
}
Use it:
self.photoView = [[MyScrollView alloc] initWithFrame:frame withDictionary:mediaContentDict withDelegate:self];
One option might be to pass in your delegate in your custom class's initializer:
-(id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary*)dictionary delegate:(id)delegate
{
self = [super initWithFrame:frame];
if (self == nil )
{
return nil;
}
self.content = [[Content alloc] initWithDictionary:dictionary];
self.delegate = delegate;
//.... other stuff
// Delegate would exist now
[self.delegate methodName:#"Test delegate"];
return self;
}

Failed to call designated initializer on NSManagedObject class

Another newbie question, just when I thought I was beginning to get a very
small handle on ios programming. Ugh! I'm following a tutoria from the
appcodeblog.com where I'm building a simple tab bar application utilizing
core data to enter, display, and search vacation destinations. I've worked
through the tutorial and have a working app, but I notice when I select the
"Show Destinations" tab I get the following error. The app seems to continue
working, but the error is logged to the console. I'm trying to debug the
issue and understand exactly what is happening, but I just don't quite
understand what is wrong. I "think" I have an issue with my
ShowDestinations.xib file where I've incorrectly hooked up my objects within
the xib. Any help is MUCH appreciated. Thanks in advance for your help and
time.
Here's the error, "CoreDataTabBarTutorial[1262:207] Failed to call designated
initializer on NSManagedObject class 'Destination'.
I'm not sure what code to provide so I've started out by showing my header
and implementation files ShowDistinationsViewController.h and
ShowDestinationsViewController.m
ShowDistinationsViewController.h
#import <UIKit/UIKit.h>
#interface SearchDestinationsViewController : UIViewController {
UISearchBar *destinationSearchBar;
UITableView *searchTableView;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSArray *fetchedObjects;
}
#property (nonatomic, retain) IBOutlet UISearchBar *destinationSearchBar;
#property (nonatomic, retain) IBOutlet UITableView *searchTableView;
#property (nonatomic, retain) IBOutlet NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) IBOutlet NSManagedObjectContext *managedObjectContext;
#end
ShowDestinationsViewController.m
#import "ShowDestinationsViewController.h"
#import "Destination.h"
#implementation ShowDestinationsViewController
#synthesize destinationsTableView;
#synthesize destinationsArray;
#synthesize fetchedResultsController;
#synthesize managedObjectContext;
// Not sure where the following code came from so I commented it out!!! It didn't seem to break anything when I commented it out
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//{
// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// if (self) {
// // Custom initialization
// }
// return self;
//}
- (void)dealloc
{
[destinationsArray release];
[destinationsTableView release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma Data Fetch from Core Data
- (void) viewWillAppear:(BOOL)animated
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Destination" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil)
{
// Handle the error.
NSLog(#"mutableFetchResults == nil");
}
[self setDestinationsArray:mutableFetchResults];
[request release];
[destinationsTableView reloadData];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [destinationsArray count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
Destination *destination = [[Destination alloc] init];
destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
cell.textLabel.text = destination.name;
[destination release];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
The problem seems to lie in
Destination *destination = [[Destination alloc] init];
destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
[destination release];
The first line is unnecessary: In Objective-C, Destination* is a pointer to the object, not the real object. The Destination object you want is presumably already in the array. So you don't have to create an object to point to, in the line [[Destination alloc] init], which is gone immediately at the next line. What's going on was
[[Destination alloc] init] creates an object a, destination points to a. a is retained by you.
(Destination *)[destinationsArray objectAtIndex:indexPath.row] gives you another object b, which is not retained by you. destination now points to b. No one holds a any longer.
release is sent to the object pointed to by destination, i.e., to b. This is against the retain-release rule; you should release a, not b!
So, instead, just do
Destination *destination = (Destination *)[destinationsArray objectAtIndex:indexPath.row];
without the release part.
As an advice: always run Analyze (which is available below the Build menu) when you build your project. The analyzer is designed to catch common types of errors, including yours. Correct your code so that all the analyzer warnings go away; you should always regard the analyzer warning as an error on your part.

How to create an Instance Variable in Objective-C

I have this example, and I would like to make my_Picture an instance variable in order to use removeFromView. Any Ideas? I got all kinds of warnings and errors trying different approaches. Thank you in advance
- (void) viewDidLoad
{
UIImageView *my_Picture = [[UIImageView alloc] initWithImage: myImageRef];
[self.view addSubview:my_Picture];
[my_Picture release];
[super viewDidLoad];
}
To make it an instance variable you would store the value in your class instead of as a temporary variable. You will also release it when your class is destroyed instead of after adding it as a subview.
E.g.
// header file (.h)
#interface MyController : UIViewController
{
UIImageView* myPicture;
}
#end
// source file (.m)
- (void) viewDidLoad
{
myPicture = [[UIImageView alloc] initWithImage: myImageRef];
[self.view addSubview:myPicture];
[super viewDidLoad];
}
- (void) dealloc
{
[myPicture release];
[super dealloc];
}