Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Chris Holloway
2,427 PointsBug squashing! Crash while trying to pass data entered on detail view to table view controller
Crash log: '[<FPLLogFlightViewController 0x10912d580> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key arrivalAirport.'
I am entering data into the following - LogFlightViewController.h:
#import <UIKit/UIKit.h>
#import "FPLFlightEvent.h"
@interface FPLLogFlightViewController : UIViewController
@property (strong, nonatomic) FPLFlightEvent *flightEvent;
at end. (not really in my code, treehouse forums auto user find function is killing me here)
LogFlightViewController.m:
#import "FPLLogFlightViewController.h"
@interface FPLLogFlightViewController ()
@property (weak, nonatomic) IBOutlet UITextField *departureField;
@property (weak, nonatomic) IBOutlet UITextField *arrivalField;
@property (weak, nonatomic) IBOutlet UITextField *totalFlightTimeField;
@property (weak, nonatomic) IBOutlet UITextField *flightDateField;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *doneButton;
@end
@implementation FPLLogFlightViewController
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.doneButton) return;
if (self.departureField.text.length > 0) {
self.flightEvent = [[FPLFlightEvent alloc] init];
self.flightEvent.departureAirport = self.departureField.text;
self.flightEvent.arrivalAirport = self.arrivalField.text;
self.flightEvent.totalFlightTime = self.totalFlightTimeField.text;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
@end
My TableViewController.h:
#import <UIKit/UIKit.h>
#import "FPLFlightEvent.h"
@interface FPLTableViewController : UITableViewController
- (IBAction)unwindToLogbook:(UIStoryboardSegue *)segue;
@end
And TableViewController.m:
#import "FPLTableViewController.h"
#import "FPLFlightEvent.h"
#import "FPLLogFlightViewController.h"
@interface FPLTableViewController ()
@property NSMutableArray *flightEvents;
@end
@implementation FPLTableViewController
- (IBAction)unwindToLogbook:(UIStoryboardSegue *)segue
{
FPLLogFlightViewController *source = [segue sourceViewController];
FPLFlightEvent *flightEvent = source.flightEvent;
if (flightEvent != nil) {
[self.flightEvents addObject:flightEvent];
[self.tableView reloadData];
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
FPLFlightEvent *flight1 = [[FPLFlightEvent alloc] init];
flight1.departureAirport = @"KRNM";
flight1.arrivalAirport = @"KNYL";
flight1.totalFlightTime = @"1.1";
flight1.flightDate = @"12 Feb 2013";
FPLFlightEvent *flight2 = [[FPLFlightEvent alloc] init];
flight2.departureAirport = @"KNYL";
flight2.arrivalAirport = @"KRNM";
flight2.totalFlightTime = @"0.9";
flight2.flightDate = @"13 Feb 2013";
FPLFlightEvent *flight3 = [[FPLFlightEvent alloc] init];
flight3.departureAirport = @"KRNM";
flight3.arrivalAirport = @"KVNY";
flight3.totalFlightTime = @"1.1";
flight3.flightDate = @"14 Feb 2013";
FPLFlightEvent *flight4 = [[FPLFlightEvent alloc] init];
flight4.departureAirport = @"KVNY";
flight4.arrivalAirport = @"KRNM";
flight4.totalFlightTime = @"1.0";
flight4.flightDate = @"15 Feb 2013";
FPLFlightEvent *flight5 = [[FPLFlightEvent alloc] initWithDeparture:@"KRNM" andArrival:@"KNYL"]; //designated initializer
flight5.totalFlightTime = @"2.0";
flight5.flightDate = @"24 Feb 2014";
FPLFlightEvent *flight6 = [FPLFlightEvent flightEventWithDeparture:@"KRIV" andArrival:@"KNID"]; //convienence contructor
flight6.totalFlightTime = @"1.7";
flight6.flightDate = @"28 Feb 2014";
self.flightEvents = [NSMutableArray arrayWithObjects:flight1, flight2, flight3, flight4, flight5, flight6, nil]; //loads dummy initial data
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#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 self.flightEvents.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"LogbookPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
FPLFlightEvent *flightEvent = [self.flightEvents objectAtIndex:indexPath.row];
cell.textLabel.text = flightEvent.flightDate;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ to %@", flightEvent.departureAirport, flightEvent.arrivalAirport ];
return cell;
}
@end
So I think that the problem occurs when I try to pass the data from the detail view to the table view. Something with the way I am formatting the NSMutableArray. Any ideas?
7 Answers
Mike Baxter
4,442 PointsI found this post on Stack-overflow. Maybe your problem is similar in using a superclass of a view instead of the view itself? Maybe check in the storyboard and see if it's using the right classes for your UITableView and so on?
Mike Baxter
4,442 PointsYou should search your code for "setValue" and see if there are any calls to "setValue:forUndefinedKey:" In Xcode, there's a search function in the upper-left that searches all your files for whatever you type.
I'm pretty sure the error message is saying that you're trying to make an NSString object (arrivalAirport) act like a NSDictionary key-value pair. (i.e., you're calling a key-value method rather than an object method.)
You could also try searching the code for the word "key". It doesn't look like there is anything in your code (from what I can tell) that should be a key-value NSDictionary; it looks like you're just using a class that has accessible strings and numbers (which are not NSDictionary objects).
I hope that makes sense, let me know if I wasn't clear enough on anything. It's more of an idea of where to look than a precise answer anyway. Cheers!
Mike Baxter
4,442 PointsMaybe you can post the header (.h) file for the "FPLFlightEvent" as well? I'd like to see what object types it uses.
Chris Holloway
2,427 PointsMike, sure. Here's the code:
FPLFlightEvent.h:
#import <Foundation/Foundation.h>
@interface FPLFlightEvent : NSObject
@property (strong, nonatomic) NSString *departureAirport;
@property (strong, nonatomic) NSString *arrivalAirport;
@property (strong, nonatomic) NSString *totalFlightTime;
@property (strong, nonatomic) NSString *flightDate;
@property BOOL isSimulator;
//designated initializer
- (id) initWithDeparture: (NSString *)departureAirport andArrival: (NSString *)arrivalAirport;
+ (id) flightEventWithDeparture: (NSString *)departureAirport andArrival: (NSString *)arrivalAirport;
@end
Chris Holloway
2,427 PointsThe types in this custom class are due to my learning process:
*totalFlightTime should be of type float but I'm still trying to figure out how to access that property type (i.e. self.totalFlightTime.????)
also *flightDate will eventually be of type NSDate but I'm still learning how to handle NSDate objects.
Right now I have everything as NSStrings for simplicity.
And I'm not doing anything with isSimulator yet...
Mike Baxter
4,442 PointsFor floats, it should look like this:
@property (weak, nonatomic) float totalFlightTime;
I'm a little rusty on my ARC memory management fundamentals, but are you sure you should be using strong for your values? I know if you use strong in the wrong places, you can get retain cycles where objects can't be released. (I guess I need to brush up on that.)
Since "arrivalAirport" is a NSString, you're probably performing some key-value operation on it (something that's only valid on NSDictionary). Any luck checking for that "setValue" or "key"?
Mike Baxter
4,442 PointsSomething you might need to know about using floats is, they're always "assigned", they're never referenced. (i.e., you can have a NSString that lives somewhere in memory and reference it, which is what that * means in "NSString *arrivalAirport". For floats, ints, chars, doubles, etc., they never get referenced, they always get assigned their own copy of the value.
Chris Holloway
2,427 PointsBecause floats, ect are primitive data types, you're right.
So far no luck with setValue or key. In my TableViewController.m viewDidLoad method I am creating an NSMutableArray:
self.flightEvents = [NSMutableArray arrayWithObjects:flight1, flight2, flight3, flight4, flight5, flight6, nil]; //loads dummy initial data
Where flight1- flight6 are dummy data generated within the viewDidLoad method. I will replace this with a real data model in the future.
And then in the same view controller, in the - (IBAction) unwindToLogbook:(UIStoryboardSegue *)segue method:
- (IBAction)unwindToLogbook:(UIStoryboardSegue *)segue
{
FPLLogFlightViewController *source = [segue sourceViewController];
FPLFlightEvent *flightEvent = source.flightEvent;
if (flightEvent != nil) {
[self.flightEvents addObject:flightEvent];
[self.tableView reloadData];
}
}
I'm passing the data recorded in the FPLLogFlightViewController to the tableview controller.
The crash occurs when I touch the + button on my table view controller...
Chris Holloway
2,427 PointsSo I fixed this by creating a private method:
- (void) loadInitialData {
FPLFlightEvent *flight1 = [[FPLFlightEvent alloc] init];
flight1.departureAirport = @"KRNM";
flight1.arrivalAirport = @"KNYL";
flight1.totalFlightTime = @"1.1";
flight1.flightDate = @"28 Feb 2014";
[self.flightEvents addObject:flight1];
FPLFlightEvent *flight2 = [[FPLFlightEvent alloc] init];
flight2.departureAirport = @"KNYL";
flight2.arrivalAirport = @"KRNM";
flight2.totalFlightTime = @"0.9";
flight2.flightDate = @"28 Feb 2014";
[self.flightEvents addObject:flight2];
FPLFlightEvent *flight3 = [[FPLFlightEvent alloc] init];
flight3.departureAirport = @"KRNM";
flight3.arrivalAirport = @"KVNY";
flight3.totalFlightTime = @"1.1";
flight3.flightDate = @"27 Feb 2014";
[self.flightEvents addObject:flight3];
FPLFlightEvent *flight4 = [[FPLFlightEvent alloc] init];
flight4.departureAirport = @"KVNY";
flight4.arrivalAirport = @"KRNM";
flight4.totalFlightTime = @"1.0";
flight4.flightDate = @"26 Feb 2014";
[self.flightEvents addObject:flight4];
}
And then calling it in ViewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.flightEvents = [[NSMutableArray alloc] init];
[self loadInitialData];
}
After entering the data on my detail view I use an unwind method to pass the data back to the table view:
- (IBAction)unwindToLogbook:(UIStoryboardSegue *)segue
{
FPLLogFlightViewController *source = [segue sourceViewController];
FPLFlightEvent *logFlightEvent = source.flightEvent;
if (logFlightEvent != nil) {
[self.flightEvents addObject:logFlightEvent];
[self.tableView reloadData];
}
}
That did the trick.
Mike Baxter
4,442 PointsOh nice! Glad you fixed it. Any idea why that works or what the problem was?