NSUnknownKeyException in Apple's HelloWorld tutorial - ios

I'm a noob to iOS development, so am following the HelloWorld tutorial here. I've got to the stage where I'm testing the app after adding the button, text field and label. I have followed the tutorial to the letter as far as I'm aware and I'm getting this error when I run the app:
2013-07-13 15:26:39.629 HelloWorld[1304:11303] * Terminating app due
to uncaught exception 'NSUnknownKeyException', reason:
'[<HelloWorldViewController 0x7566000> setValue:forUndefinedKey:]:
this class is not key value coding-compliant for the key label.'
* First throw call stack: (0x1c90012 0x10cde7e 0x1d18fb1 0xb79e41 0xafb5f8 0xafb0e7 0xb25b58 0x22f019 0x10e1663 0x1c8b45a 0x22db1c
0xf27e7 0xf2dc8 0xf2ff8 0xf3232 0x423d5 0x4276f 0x42905 0x4b917 0xf96c
0x1094b 0x21cb5 0x22beb 0x14698 0x1bebdf9 0x1c13f3f 0x1c1396f
0x1c36734 0x1c35f44 0x1c35e1b 0x1017a 0x11ffc 0x1f9d 0x1ec5)
libc++abi.dylib: terminate called throwing an exception
The code generated in HelloWorldViewController.m is:
#import "HelloWorldViewController.h"
#interface HelloWorldViewController ()
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UITextField *textField;
- (IBAction)changeGreeting:(id)sender;
#end
#implementation HelloWorldViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)changeGreeting:(id)sender {
}
#end
And in HelloWorldViewController.h:
#import <UIKit/UIKit.h>
#interface HelloWorldViewController : UIViewController
#end
I tried using this answer but I can't see an XIB file (I think because I'm using a Storyboard?) and I can't see any obvious discrepancies in the VC.
Please help.

A storyboard is a single file that encapsulates a collection of XIB files. Each "scene" in a storyboard represents what would otherwise be a single XIB file.
In the storyboard...
(1) Select the View Controller in the relevant scene.
(2) Open the Identity Inspector (third tab in the right-hand Utilities pane). Check that the view controller's class is correctly set to HelloWorldViewController.
(3) check that the View Controller's IBOutlets are correctly wired up to the correct views. (Ctrl-click on each view and check it's settings in the HUD).
'Wiring up' entails CTRL-dragging from your viewController to the relevant view in your storyboard scene. A list will appear of appropriate IBOutlet properties to select.
These properties can be placed either in the interface declaration in the .h file or in a class extension in the .m file.
An interface declared as #interface (in the .h file) is public; A class extension declared as #interface() (usually in the .m file) is private to the class (although nothing is completely private in Obj-C). Class extensions are useful for declaring private properties, or properties that are publicly readonly and privately readwrite. See the apple docs. They used to be good for declaring private methods, but now this is redundant: methods only need declaring if we want to make them public.
A good rule of thumb is wherever possible, keep your declarations in the class extension and out of the .h file. These days this should only apply to properties as method declarations are not required unless making them public.
You mentioned that you fixed your problem by moving your property declarations from the class extension to the public interface. This is puzzling, as both locations are normally acceptable for this use.

I removed all referencing outlets and actions which you can see at connection indicator while selecting objects one by one at storyboard workspace, and deleted some codes added automatically by xcode.
And then I made them by following tutorials again. finally it worked fine.

Related

Different methods for IBOutlet creation

There are at least 3 methods of creating an IBOutlet in Objective-C, for making iOS 10 App, in Xcode 8.
Method 1: in ViewController.h
#interface ViewController : UIViewController
#property (nonatomic, strong) UILabel *textLabel;
#end
Method 2: in the interface of ViewController.m
#interface ViewController () {
IBOutlet UILabel *textLabel;
}
#end
Method 3: in the interface of ViewController.m, using #property
#interface ViewController ()
#property (nonatomic, strong) UILabel *textLabel;
#end
Given that the textLabel has to be accessed & its text is needed to be updated frequently, which method is the correct way to do so?
That all depends on whether you need your outlet to be accessible to classes outside of the containing one; generally I would discourage this because it is good practice to keep your view controllers responsible for updating your UI and not pass this task around to other classes. With this being said, Method 3 would be the best option, however, if you do have to access your object from another class, then simply use Method 1 so it is exposed in your class header.
Method 2 utilises iVars rather than object properties and is not the proper way to declare outlets, it may even cause unexpected behaviour so it is best to avoid this method.
Your code contains no proper IBOutlet. Outlets are connections to Storyboard.
Method 1
This is a property. As it is in .h file, it can be reached from outside. The Objective-C pattern for public.
Method 2
This is an iVar. Do not use iVars if you do not have to.
Method 3
This is a property. As it is in .m file, it can not be reached from outside. The Objective-C pattern for private.
Method 4
A proper IBOutlet looks like this:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UILabel *label;
#end
It is a simple property. You have to decide if you put it in .h or .m file depending on whether or not you want to publish it.
The IBOutlet simply makes the property connect-able to Storyboard. It's an annotation for Xcode and does not alter the semantic of your code.
Edit 1:
As Sulthan correctly mentions in the comments:
In most situations the correct design pattern is to hide outlets because it's an implementation detail. External classes should not set data directly using views.
Edit 2:
Why "not to use iVars if you do not have to" (2)
Opinion based:
I consider it as good OOP practice to use getters & setters (and thus not to access the variables directly). Also code is easier to read as you know while reading what x = self.variable (property) and x = variable (local variable) are.
If you have to use iVars for some reason, it is common to (and I would recommend to) prefix the name with _. x = _variable (iVar).

how to slim down view controllers in iOS?

How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.

Accessing a method on a views superview - What is UIViewControllerWrapperView?

My problem is a follows
I have a UIViewController subclass which holds a UISegmentedController and four tableviews that I layed out in interface builder.
#interface MultiTableHoldingView : UIViewController{
}
#property (strong, nonatomic) IBOutlet DataTV *dsDataTV;
#property (strong, nonatomic) IBOutlet EnviroTV *dsEnvironmentTV;
#property (strong, nonatomic) IBOutlet LocationTV *dsLocationTV;
#property (strong, nonatomic) IBOutlet Note_AnimalTV *dsNoteAnimal;
#property (strong, nonatomic) IBOutlet UISegmentedControl *diveElementSegmentController;
#property (strong, nonatomic) DiveSite* currentSite;
- (IBAction)diveElementSegmentControllerDidChange:(UISegmentedControl *)sender;
-(void) setFreshWaterColor;
-(void) setSaltwaterColor;
#end
setFreshWaterColor and setSaltWaterColour just set the background colour properties of the MultiTableHoldingView instances UIView and the four tableviews it contains. Both these method work fine when called from MultiTableHoldingView's viewDidLoad method. Heres one of them
-(void) setSaltwaterColor{
DLog(#"in set salt water colour");
self.view.backgroundColor= SaltWaterColor;
_dsLocationTV.backgroundColor=SaltWaterColor;
_dsDataTV.backgroundColor=SaltWaterColor;
_dsEnvironmentTV.backgroundColor=SaltWaterColor;
_dsNoteAnimal.backgroundColor=SaltWaterColor;
}
The other is the same except sets to FreshWaterColor - both are #define i have set up.
I use the segmentedController to turn the hidden properties of the various tableviews on and off. All nice and simple. The tableviews are pulling in their data. Working fine.
When selecting one of my tableview cells on one of the tableViews I want to change the background colour of both my tableview ( in fact all of my tableviews ) and the UIView that is the superview
self.superview.backgroundColor = FreshWaterColor;
works fine for reaching back and changing the instance of MultiTableHoldingView views background property but I want to call the instance of MultiTableHoldingView's setFreshWaterColor and setSaltwaterColor methods.
I have imported MultiTableHoldingViews header into the relevant tableview (EnviroTV), so it knows about it its superviews methods. But if I try to call either of the two methods on self.superview the methods do not show up and if i type them in full I get an the following error
no visible interface for 'UIView' shows the selector 'setFreshWaterColor'
So i checked what kind of object the superview was and its a "class of superview UIViewControllerWrapperView"
I search on this and its apparently "
This is a private view used by the framework. You're not supposed to modify it or whatsoever."
I'm obviously missing something here - how should i call the method on the instance of MultiTableHoldingView ?
Thanks in advance
Simon
Doh - its just delegation as danypata mentions in the comments - i've posted exactly how I did this as an answer below. Tried to make it as clear as possible how delegation works
THE SOLUTION
Step one - get more sleep before coding .
This really is basic objective-c stuff - I just went off at a tangent, looking for someway else to do it, getting confused by my discovery of UIViewControllerWrapperView along the way.
The solution, as danypata rightly suggests in the comments, is to use delegate -a common design pattern in Objective-C - just like you do, for example, when you use another class to supply tableview data
As I've been a numpty and wasted hours of my time today I'll try and make the 'how' clear for other relative newbies or people having an off day and not thinking straight.
In my case I set this up as follows
In my subview class's interface file - EnviroTV.h - I define the following protocol just before the #interface declaration
#protocol EnviroTVProtocol <NSObject>
-(void) setFreshWaterColor;
-(void) setSaltwaterColor;
#end
Then in the #interface section of the same file I add a property of type id which must conform the protocol I just declared .
#property (nonatomic, strong ) id<EnviroTVProtocol> colorChangeDelegate;
You make the type an id - a generic object - as you really don't care what kind of object is going to act as your delegate just that it implement the methods that you need it to run. When an object declares itself to implement a protocol its just promising to implement the method(s) that are required by the protocol
So, when I want to run the methods on the superviews class I call
[self.colorChangeDelegate setFreshWaterColor];
Or
[self.colorChangeDelegate setSaltWaterColor];
The final piece of the delegation pattern is to go into the class thats going to be the delegate (in this case my MultiTableHoldingView class ) and state that it conforms to the protocol
I do this in the MultiTableHoldingView.h file
Changing this line :
#interface MultiTableHoldingView : UIViewController
into this line :
#interface MultiTableHoldingView : UIViewController <EnviroTVProtocol>
means this class promises to implement all the required methods of the EnviroTVProtocol.
Luckily I had already written the two methods. So when I compiled it ran correctly
Newbies - don't be afraid of delegation - its awesome and not as complex as you first imagine it to be
Meanwhile, if anyone can explain what UIViewControllerWrapperView is .....

issue with ivar

I'm subclassing a UIToolbar because I'm gonna reuse it all over my app. The UIToolbar uses a delegate protocol:
//
// UIToolbarCustom.h
//
#import <UIKit/UIKit.h>
#protocol UIToolbarCustomDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface UIToolbarCustom : UIToolbar {
id <UIToolbarCustomDelegate> delegate;
}
#property (strong, nonatomic) id delegate;
#end
The standford iOS development course teacher recommends to explicit declare all the ivars prefixing it with a underscore, like:
#implementation UIToolbarCustom
#synthesize delegate = _delegate;
#end
But, in this specify scenarion it gives me a error:
error: property 'delegate' attempting to use ivar '_delegate'...
The code works just fine if I use:
#synthesize delegate = __delegate; or
#synthesize delegate;
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
UPDATE
Thank all you guys for all the clarifications and protips, I'm learning a lot. Turns out that I'm new to iOS development (this is my first app second version, so I'm trying to do it right =p). Following the tips I came out with this new header file:
//
// Toolbar.h
//
#import <UIKit/UIKit.h>
#protocol ToolbarDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface Toolbar : UIToolbar
#property (strong, nonatomic) id delegate;
#end
Notes:
The class prefix was removed.
The delegate declaration was removed (I'm using a ios delegate tutorial code, but the code sample uses a older xcode version, where the declaration is needed).
The synthesize was removed, I also didn't knew that we don't need synthesize our properties anymore.
PS: Obviously the code does not work, because the ivar problem. I'm gonna change its names, so I don't need to synthesize it, not sure about what name to use anyways...
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
Yes, that's exactly the problem. You need to come up with a different name for your instance variable. __delegate will work, or you could prefix the name with a 3 letter prefix (see last paragraph).
Do note that you've declared your ivar as delegate, then in the synthesize statement told the compiler to use _delegate. Effectively that means that your delegate ivar isn't being used at all. In any case, if you're writing for iOS (as opposed to 32-bit Mac), like you are, you don't need the explicit instance variable declaration in your subclass's #interface section, because the compiler will automatically create it for you.
Finally, it's bad form to name your own subclass something that begins with 'UI', since the UI prefix is reserved for classes that are part of UIKit. You should use your own 3 letter prefix instead, or else no prefix at all. The problem is that a future version of UIKit could conceivably include a class called "UIToolbarCustom", and your subclass would collide with it.
Since last year, when Xcode 4.3 came out, you don't need to synthesize your properties. It is done for you by the compiler (an ivar is generated, and a leading underscore is added to its name). This means that you also don't need to declare an ivar. If you do, be sure to name it something other than _delegate.
So, all you really need is this line:
#property (strong, nonatomic) id<UIToolbarCustomDelegate> delegate;
UPDATE: please see the Andrew Madsen's answer for the full story. Turns out UIToolbar has its own ivar named _delegate. Who knew!

Set Delegate for Subview Controller

i'm sure there is a simple way to solve this problem, but I can't figure out.
I got a TabBarViewController with several Views. In some of the Views i loaded Tableviews with XML based content.
My XML Parser works fine, I tested it before in a separate Projectfile.
The Problem is that my TableViewController, for which I created a XMLAppDelegate to manage the parsing of my xmlfiles, still sends the methods to the main delegation file of my Project.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MainAppDelegate slices]: unrecognized selector sent to instance 0x6d1fd00'
Like the error message shows, he tries to send it to my MainAppDelegate, instead of the XMLAppDelegate.
I implemented the XMLAppDelegate in my Controller Files and init the delegate this way:
The .h File of my Controller
#import <UIKit/UIKit.h>
#class XMLAppDelegate, NewsDetailViewController;
#interface NewsViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *newsTableView;
XMLAppDelegate *appDelegate;
NewsDetailViewController *ndvController;
}
#end
The .m File of my Controller
- (void)viewDidLoad {
[super viewDidLoad];
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
self.title = #"Slices";
}
The Controller is loading into the TabBarView as separate .xib file.
In this nib file i connected the Delegate and Data Source to my XMLAppDelegate.
I still get this Error in the Log and the Application crashes as I try to switch to the Tab wish the TableViewController in it.
Hope you understand my problem. Maybe someone could tell me what I'm doing wrong here setting the Delegate to my XMLAppDelegate.
EDIT:
To explain what I want to do:
I have a XMLParser class to parse the File, a Slice class to store the Elements and XMLAppDelegate. From this files i get my XML results stored in an Array with name "slices".
To use the Elements of the Array, for showing it up as Table or textlabel, I connected the TableViewController to the XMLAppDelegate (which parses my XML Document using the XMLParser File and stores Data in the Array).
The Items of this Array are previously declared in the Files as Strings like this
#property (nonatomic, readwrite) NSInteger sliceID;
#property (nonatomic, retain) NSString *image;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *text;
But like i said, the parser works.
I think my problem seems to be that I requested appDelegate.slices, but the selector is not my XMLAppDelgate. The Error says it uses the Main Delegate, which don't have any propertys of the xml Delegate file.
The TabView loads the NewsViewController, which calls for the array in the XMLAppDelegate.
I implemented the files, connected the Delegate to TableView as Data Source and Delegate, but still it seems to take the main delegate.
That drives me crazy.
The Project is a Company Profile for a great Wellness Motel.
I get the Contents from the CMS as XML-Files and need to access them from XMLAppDelegate, that delivers the sites contents.
Hope you understand my bad English. ;)
So, now you've declared the property, but you haven't implemented it. A property declaration, among other things, declares that you will implement one or two accessor methods for the property. So, it's not (yet) enough just to declare the property; you must also implement the accessor methods that make that property real at run time.
The easiest way to fix this is to synthesize the accessors for the slices property. If you need some custom behavior, you can implement them yourself, but it doesn't sound like it—synthesizing is not only easiest, but probably the right solution.
See the documentation on properties for more information.
Maybe I have no idea how about your XMLappDelegate, but in my opinion
[[UIApplication sharedApplication] delegate]
always gives you the main AppDelegate, whatever you are casting it into.
Maybe you should add a reference to your XMLAppDelegate to your Main App Delegate and declare it as a property, then you could access the XMLAppDelegate by
AppDelegate.xmlDelegate
Then again I don't really understand what you are trying to do..
Maybe it helos anyway ;)

Resources