I am trying to create my first test app in IOs and everything I do gets me that error. I am using xcode 4.4.
The app is very simple. It has a button, and When I press it, a label and an imageview must appear.
My whole code is this:
ViewController.h
//
// ViewController.h
// helloWorld_04
//
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
IBOutlet UILabel *label;
IBOutlet UIImageView *Kant;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, retain) IBOutlet UIImageView *Kant;
- (IBAction)buttonGuess:(id)sender;
#end
and my implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize label,Kant;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)dealloc {
[label release];
[Kant release];
[super dealloc];
}
- (IBAction)buttonGuess:(id)sender {
label.text=#"Hello World i am back!";
UIImage *imageSource=[UIImage imageNamed:#"kantStair.png"];
Kant.image=imageSource;
}
#end
My error log is this:
2012-08-23 13:38:50.030 helloWorld_04[537:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<ViewController 0x6a5e1f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key image.'
*** First throw call stack:
(0x14b2022 0xeb2cd6 0x14b1ee1 0x9c3022 0x934f6b 0x934edb 0x94fd50 0x23771a 0x14b3dea 0x141d7f1 0x23626e 0xdc1fc 0xdc779 0xdc99b 0x3b401 0x3b670 0x3b836 0x4272a 0x2d1b 0x13386 0x14274 0x23183 0x23c38 0x17634 0x139cef5 0x1486195 0x13eaff2 0x13e98da 0x13e8d84 0x13e8c9b 0x13c65 0x15626 0x2a22 0x2995)
terminate called throwing an exception(lldb)
and it gets me that signal in that line:
//
// main.m
// helloWorld_04
//
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
I have read several answers here but not found sollution to my problem, that why I made it a new question. I thought that it may be a problem with the connection so what I did on my own was to "darg and drop" my label and my image to "file's owner" but still getting the error.
Looking at your error message, it looks like you have something defined as image in Interface Builder, but doesn't exist. E.g., maybe you have something like:
But you don't have a image property. Did you have one once upon a time, perhaps having renamed it to Kant? If you have something like this defined in Interface Builder, delete it (by tapping on the "x" next to the outlet that I've highlighted) and then link it up again to your new control.
Update:
You should definitely fix your bug above, and hopefully the above observation helps you find it. There is not a bug in your code, but rather the problem undoubtedly rests with your Interface Builder linkages.
But, having said that, if you're a new programmer, I hope you don't mind some unsolicited stylistic observations. Clearly, given that it is a matter of style, these can be debated, but I think these all represent either established or emerging iOS coding standards. Anyway, I might suggest that in the future:
Like David H suggested, you should use lower case variable names.
You probably should have #synthesize statements that either say #synthesize label = _label, or, if you're using Xcode 4.4 or later, just omit the #synthesize statement altogether. (I know that Interface Builder can generate a simple #synthesize statement for you, but it really is best practice to #synthesize with a unique instance variable name so you don't accidentally confuse instance variables with properties.)
You should reference your instance variables in init and dealloc methods (i.e. the variable name with the leading underscore) and elsewhere use the property (with the leading self.), as noted by Born Survivor.
You probably should omit the instance variables and let the #synthesize statement do these for you (so that if you make a typo, you don't accidentally end up with two instance variables).
Thus your code would then become:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
// note, no braces with instance variables defined
// once upon a time that was recommended by Apple, but no longer
// just let the following #property statements and the subsequent
// #synthesize statement generate the instance variables for you.
#property (retain, nonatomic) IBOutlet UIImageView *kant; // note the lower case "k"
#property (retain, nonatomic) IBOutlet UILabel *label;
- (IBAction)buttonGuess:(id)sender;
#end
and
// ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize label = _label; // note the #synthesize statement let's us define what the instance variable name should be, _label in this case
#synthesize kant = _kant;
- (void)viewDidUnload
{
[self setKant:nil];
[self setLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)dealloc {
[_kant release]; // note I'm now using the instance variables that begin with the underscore
[_label release];
[super dealloc];
}
- (IBAction)buttonGuess:(id)sender
{
self.label.text = #"Hello World i am back!"; // note, I'm using the properties with the preceding "self."
UIImage *imageSource = [UIImage imageNamed:#"kantStair.png"];
self.kant.image = imageSource;
}
#end
Its important in ObjectiveC to always name your variables with a lower case letter - because when you synthesize a variable like "foo" you get "-(id)foo;// the getter" and "-(void)setFoo:(id)val;//the setter". See how the setter uses a capital letter. So first thing you should do is rename 'Kant' to 'kant'. [by convention only Classes have initial capital letters, so you help others like me read your code by following the conventions.]
So first thing you do is change 'Kant' to 'kant', and then go back to the Interface builder view and re-wire the newly named variable to the UIImageView.
If that does not fix the problem, you have iswired 'kant' or there is some other oddity going on - add this line of code right before you set the image:
NSLog(#"kant has class %#", NSStringFromClass([kant class]) );
and lets see what it really is.
Related
I have some abbreviated iOS Objective-C sample code (simplified from a larger project) that causes a crash in NSUndoManager that I can't explain.
Namely, when an object that is only held onto by the NSUndoManager deallocs (because it's beyond the levels of undo), and, according to the docs calls removeAllActionsWithTarget:self, I get an EXC_BAD_ACCESS.
// SimpleViewController.m
#interface ViewController ()
#property (nonatomic, strong) NSUndoManager *undoManager;
#end
#implementation ViewController
#synthesize undoManager;
// called from a simple button
- (IBAction)doItTapped:(id)sender
{
CoolObject *object = [CoolObject new];
object.undoManager = self.undoManager;
// according to docs, object will be retained by NSUndoManager here
// but target will not (which should be okay)
[self.undoManager registerUndoWithTarget:self selector:#selector(notCool:) object:object];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.undoManager = [NSUndoManager new];
self.undoManager.levelsOfUndo = 3;
}
and
// CoolObject.m
#implementation CoolObject
- (void)dealloc
{
[self.undoManager removeAllActionsWithTarget:self];
}
#end
After the 4th tap of the button (levelsOfUndo + 1), it crashes.
If I swap NSUndoManager with GCUndoManager, no crash.
Tested in iOS 10.2 sim and devices.
Thanks for any ideas!
Their are chances that you might be getting this error because self.undoManager is not retained at that point where you are using it. When the object is already deallocated and you try to access it, you will get bad access exception.
Try to change your code from this:
CoolObject *object = [CoolObject new];
to this:
#interface ViewController (){
CoolObject *object;
}
#property (nonatomic, strong) NSUndoManager *undoManager;
#end
#implementation ViewController
- (IBAction)doItTapped:(id)sender
{
object = [CoolObject new];
object.undoManager = self.undoManager;
// according to docs, object will be retained by NSUndoManager here
// but target will not (which should be okay)
[self.undoManager registerUndoWithTarget:self selector:#selector(notCool:) object:object];
}
#end
Hope this will help.
Just like me, you seem to have misinterpreted the admittedly inaccurately written documentation. The docs talk about "target", "object" and "target object" as if they were different things when they really mean exactly one and the same: the (id)target parameter of -removeAllActionsWithTarget:
In other words, in my opinion you should not need to call -removeAllActionsWithTarget: inside of CoolObject at all because CoolObject has been specified as the object of -registerUndoWithTarget:selector:object: whereas the target is your ViewController.
You may have to call -removeAllActionsWithTarget: in your NSViewController's -dealloc but even that is unnecessary in your example because your NSViewController owns the NSUndoManager and thus ViewController won't go away before undoManager does.
Alright, so I'm trying to do something very, very simple: Multiplying the user input from one textfield by another textfield and feeding out the answer through a label. There are no error messages, but when I try to run the app, the simulator screen goes black and Xcode says this:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key outputlabel.'
I have no idea why it is doing this. Any suggestions? Please be extremely specific as I am new to programming.
My code:
//
// ViewController.h
// Cramer
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
// Objects are given addresses:
#property (weak, nonatomic) IBOutlet UITextField *box_a;
#property (weak, nonatomic) IBOutlet UITextField *box_b;
#property (weak, nonatomic) IBOutlet UILabel *hiLabel;
#property (weak, nonatomic) IBOutlet UIButton *clickButton;
#end
AND
//
// ViewController.m
// Cramer
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (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.
}
// Math takes place:
- (IBAction)clickButton:(id)sender {
NSInteger number1 = [self.box_a.text integerValue];
NSInteger number2 = [self.box_b.text integerValue];
NSInteger prod = number1 * number2;
self.hiLabel.text = [NSString stringWithFormat:#"%#", #(prod)];
}
#end
It seems like in your view controller XIB file, created using the Interface Builder or Storyboard graphic editor, you have some view (probably a UILabel) connected to a "outputlabel" property of the File Owner (that is your ViewController class) which doesn't exist.
Typically this happens when you initially connect an object from the XIB to a new outlet in the code, then you rename the outlet in the code but you forget to reconnect the object in the XIB to the new reanmed outlet. It could be, in your case, that you initially connected the output label to a IBOutlet property called "outputlabel", then you renamed it to "hiLabel" but you forgot to reconnect the label in the XIB to the new "hiLabel" IBOutlet.
To verify this you can look at all your objects in the view controller graphical interface, right-click on each of them and see their outlet connections and check that they point to properties effectively defined in the class.
your label on your storyboard is hooked up to a UILabel in your view controller named "outputlabel". However in your view controller you have it named "hiLabel". If, in interface builder, you click on your label then go to view -> utilities -> connection inspector you'll see the connections on the right hand side and should be able to verify what it's connected to. Either delete the connection and start over or change the name of your label in your view controller.
In the last line [NSString stringWithFormat:#"%#", #(prod)];, why are you using %#? NSInteger is a primitive type, not an object. It seems to me you should use a %d so that the line would read [NSString stringWithFormat:#"%d", prod];.
ETA: Use %ld instead of %d.
I am having a label code for "decisionText" inside dot-m file as follows :
#synthesize decisionText ; //<<<This generates the error
inside dot-h file, the code is written as follows:
IBOutlet UILabel *decisionText
The error i get is :
No declaration of property 'decisionText found in the interface.
ps: In the interface builder when i click the label, i can find the name "decisionText" under Referencing Outlets mapped with File's Owner
Stuck on this. :(
As suggested I removed line #synthsize decisionText and used :
#property (nonatomic,weak) IBOutlet UILabel *decisionText ;
Now i get the error :
Expected a property attribute before 'weak'
Dot M file :
#import "ClickButtonViewController.h"
#implementation ClickButtonViewController;
//#synthesize decisionText ;
#property (weak,nonatomic) IBOutlet UILabel *decisionText ;
-(IBAction)buttonPressed:(id)sender
{
decisionText.text = #"Go for it!" ;
}
-(void)dealloc{
[decisionText 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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#end
in the .h file add:
#interface ViewController : UIViewController
{
//....
IBOutlet UILabel *decisionText ;
//...
}
#property (nonatomic, retain) IBOutlet UILabel *decisionText ;
//...
#end
then in the .m file add:
#synthesize decisionText ;
You use #synthesize statements with declared properties. Thus, your code should probably look like:
#interface ViewController : UIViewController
{
// your ivars go here
// but this is not needed:
//
// IBOutlet UILabel *decisionText;
}
// your properties go here
#property (nonatomic, retain) IBOutlet UILabel *decisionText;
#end
If you're using ARC, replace retain with weak.
And in your .m file, you would have:
#implementation ViewController
#synthesize decisionText = _decisionText;
// and your implementation goes here
Note:
While you can explicitly declare your instance variable, if you omit it, the #synthesize statement will create one for you. Thus, you don't need to explicitly declare any instance variable. In fact, I might argue that you should not explicitly declare your instance variable because if you have a typo, it only presents an opportunity to accidentally end up with two instance variables, the one you explicitly declared and the one the compiler will generate. I've seen that problem here on Stack Overflow more than once. So, in my example, I've omitted the explicit instance variable declaration and I'll let the compiler take care of it for me and it minimizes the chance for error.
While not required, it is often advised that #synthesize statements specify a different name for your property's instance variable (e.g., in this case, I'm suggesting that the property decisionText would have an instance variable of _decisionText). This helps discourage the accidentally reference to instance variables when you meant to invoke the property's getter or setter. (In fact, in Xcode 4.4 and later, if you omit the #synthesize statement, the compiler will automatically synthesize the instance variable for you with the leading underscore.) Thus, in your code, you would then refer to the property self.decisionText or to the instance variable _decisionText. It's generally not so critical for IBOutlet objects, but as you start to use your own custom properties, this convention becomes useful.
Alternatively, if you are using Xcode 4.4 you can use autosynthesis.
In which case you don't need to declare the iVar you can just write:
#property (weak, nonatomic) IBOutlet UILabel *decisionText;
And you don't need to write the #sythesize line at all.
If you do this - be aware that the generared iVar will have a leading underscore appended by default, although you should just stick to using the property accessor in this case so it makes little difference.
You can see what you can do in the Objective-C Features Availability Index
Change
IBOutlet UILabel *decisionText
to
#property (nonatomic, weak) IBOutlet UILabel *decisionText
You can only synthesize properties you defined like that with the #property keyword
You declared only the instance variable which will store the content of your property but you didn't declare the property itself. I think that the easiest way to solve that is to add in your public interface (.h file) or in your private interface (#interface ClassName () ... #end in ClassName.m file) the declaration of the property.
ClassName.h
#interface ClassName : ParentClass
#property (nonatomic, weak) IBOutlet UILabel decisionText; //This is the declaration of the property than you can ctrl-drag to wire it up to your label
#end
ClassName.m
#implementation ClassName
#synthesize decisionText = _decisionText //the _decisionText stuff is the name of the instance variable that will store the content of your property
... //your methods
#end
When I try to compile this I get this error. What do I need to add for the property declaration in the interface? If textBox is an instance variable, why does it need to be declared as a property?
ViewController.h
#import <UIKit/UIKit.h>
#interface TNRViewController : UIViewController {
IBOutlet UITextField *textBox;
IBOutlet UILabel *label;
}
- (IBAction)button:(id)sender;
#end
ViewController.m
#import "TNRViewController.h"
#implementation TNRViewController
#synthesize textBox;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)dealloc {
[textBox release];
[label release];
[super dealloc];
}
- (IBAction)button:(id)sender {
NSString *Name = textBox.text;
NSString *Output = Nil;
Output = [[NSString alloc] initWithFormat:#"%# says: Hello World!", Name];
label.text = Output;
[Output release];
}
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[textBox resignFirstResponder];
return YES;
}
#end
textBox needs to be declared as a property because you are #synthesizing it in your implementation.
You need to either:
Add the #property declaration for textBox in your interface.
OR, You could remove the #sythesize line from your implementation if you don't plan on needing the setter/getter methods.
by writing #synthesize textBox in your implementation the compiler generates 2 methods for you automatically.
-(UITextField*)textBox
-(void)setTextBox:(UITextField *)textBox
To be accessed these need to be defined in the class' interface. Objective-C for the iPhone has a nifty shortcut for declaring these two methods, the #property directive. You can also include information about how the variable should be stored in this directive.
#property (nonatomic, retain) IBOutlet UITextField * textBox
Would give you your IBOutlet for a text field. It is also a stand in for the 2 methods above. It tells us that the textBox is retained by your class. By always using the setter and getter methods for a variable you can avoid releasing an object and referencing the instance variable later, when it may not be safe. It is best practise to do this. You would access the text field from within your class by doing
[self.textBox setText:#"aString"];
self.textBox.text = #"aString";
(the lines above are equivalent)
This error happened when I added a pod. I ended up deleting a updating my pod file and it fixed the error.
I have been playing a bit with the memory in order to be a good memory citizen on the iPhone SDK.
However I still struggle to understand the difference between "self.something" and just "something".
As far as I understood, "self.something" means ask to the class for "something", but there is something wrong on my thought. Let's see the example:
I have worked with the memory releasing:
[self.labelIBOUtlet release] -> It crash
[labelIBOUtlet release] -> It doesn't.
Can anyone please explain me what is the reason?
Thank you!
EDIT:
This is the information I have set on the header file:
#interface viewController : UIViewController {
UILabel * labelIBOutlet ;
}
#property (nonatomic,retain) IBOutlet UILabel * labelIBOutlet ;
You have to understand the meaning of "property"
the use of "dot" is just a faster way to call "special methods" created just to "set" and "get" variable-property.
as example, you could have your own class/UIView which uses a subView:
in myView.h
#interface myView : UIView {
UIWebView *webView;
}
if you do just this you have not a "property", but just an ojbect...
so in your myView.m you try to use the "dot" like this:
NSLog(#"%i", self.webView.frame.size.width);
then you get an error, you cannot do that, xCode says:
error: accessing unknown 'webView' getter method
that just means that a the method "webView" doesn't exist...
'couse when you call "self.webView" you just call a method called "webView"...
this method just return the pointer to your value.
and when you call:
self.webView=someValue;
you are just calling the method "setWebView", a method that just set your object with someValue...
but so... where do those 2 invisible methods come from?
they are created by xCode itself if you tell it to use webView as a property...
in our example, add some lines:
in myView.h
#interface myView : UIView {
UIWebView *webView;
}
#property (nonatomic, retain) UIWebView *webView;
in myView.m
#implementation myView
#synthesize webView;
// ...
doing this xCode will add the 2 methods "webView" and "setWebView" for you,
and now you can call:
NSLog(#"%i", self.webView.frame.size.width);
with no error...
and you can put value (of the right format, in this case a pointer to an existing UIWebView)
just calling:
self.webView = aUIWebView;
and remember to release it, 'couse you used "retain" in :
#property (nonatomic, retain) UIWebView *webView;
release it with:
[webView release];
Did you #synthesize labelIBOutlet in the implementation file?
If you do not have labelIBOUtlet in your object declared it will fall on calling self.labelIBOUtlet because it do not exist.
self == is in the object which is declared in header file
hope it makes it clear