I made a simple subclass of UILABEL called CommaLabel that will eventually insert commas into a numeric string, like apple's calculator does. The compiler says my implementation is incomplete. Stupid question: what's missing? (I also don't understand what I have to do regarding memory management in here :-/) (i'm probably going to end up just implementing the processing code in the view controller but i just want to see how this would look anyway at this point...)
#import <Foundation/Foundation.h>
#interface CommaLabel : UILabel
-(void)text:(NSString *)text;
-(void)setText:(NSString*)text;
#end
#import "CommaLabel.h"
#implementation CommaLabel
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
-(NSString *) text{
return super.text;
}
-(void)setText:text
{
super.text=text;
}
#end
What's incomplete?
This, in the header:
-(void)text:(NSString *)text;
Doesn't match this, in the body:
-(NSString *) text{
return super.text;
}
Thus, the function specified as existing in the header is not in the body. That generates a compiler warning that the implementation is incomplete.
I think you would do well to start with a book or tutorial about Objective-C and iPhone programming. There is no need to write these setter and getter methods out explicitly instead of using #property and #synthesize. However, to address the immediate problems, your .h should read:
-(NSString*)text;
-(void)setText:(NSString*)newText;
and the .m should read:
-(NSString*)text{
return text;
}
-(void)setText:(NSString*)newText {
text = newText;
}
Usually it's a good idea to copy and paste the methods from the .h to the .m to ensure that they match exactly.
Related
I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.
I am having some issues with my protocol & delegate that I have set up in my app.
I am trying to return some data from a class back to a viewcontroller, however when I try to send it back nothing happens... The protocol method is never entered.
I have been over the way have set it up several times using this as a reference and just cannot see where I am making the error, So I thought if I share my code maybe someone here might be able to see what I cannot.
Heres the code I have written.
SendingClass.h
#protocol SearchViewCachedData <NSObject>
- (void)sendMyArray:(NSArray *)array;
#end
//..
__weak id <SearchViewCachedData> SearchViewDelegate;
//..
#property (weak, nonatomic) id <SearchViewCachedData> SearchViewDelegate;
//..
SendingClass.m
#synthesize SearchViewDelegate;
//..
[[self SearchViewDelegate]sendMyArray:dictionaryArray];
SearchView.h
#interface SearchViewController : UITableViewController <SearchViewCachedData> {
SearchView.m
- (void)sendMyArray:(NSArray *)array
{
//Break point in here.. but its never reached.
}
Going abit bonkers here so any help what so ever would be greatly appreciated.
I have a feeling your delegate is not set
Check to make sure searchViewDelegate is set to an instance value
if (self.searchViewDelegate != nil) {
[self.searchViewDelegate sendArray:array];
}
Also. Properties should have their first case lower case. Classes are the items that are Capitalized.
amendment
It may be getting set to nil by another part in code or you may not be setting it at all.
where you synthesize your delegate you can create a setter as well.
#synthesize searchViewDelegate = _searchViewDelegate;
- (void) setSearchViewDelegate:(id<SearchViewCachedData>) searchViewDelegate{
if (searchViewDelegate != searchViewDelegate){ // Add breakpoint here to see when set is called.
searchViewDelegate = searchViewDelegate;
}
}
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.
In .h file
#interface ViewController : UIViewController {
#private int intVariable1;
}
#property (readwrite,assign) int iVar;
-(void)Callme;
#end
In .m file
#implementation ViewController
#synthesize iVar=intVariable1;
-(void)Callme
{
NSLog(#”Callme called”);
}
-(void)setIVar:(int)inIVar
{
intVariable1 = inIVar;
[self Callme];
}
#end
I have implement this code to call "Callme" function when the variable state changes, But when i call the function setIVar in viewDid load it does not work, Any idea of calling this?
Way i used to call
[self setIVar:3];
If you want to provide your own implementation for getter/setter functions do not use the #synthesize directive in your implementation! This will generate its own -(void)setIVar:(int)inIVar and -(int)iVar methods and these might hide your version. In turn, if you want a readwrite property, you'll also have to implement the getter i.e. -(int)iVar.
Simple remove the #synthesize iVar=intVariable1; line from your implementation and put implement also -(int)iVar.
I'm confused - I cannot understand what is the delegate is for?
The Application Delegate which is created by default is understandable, but in some cases I've seen something like this:
#interface MyClass : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
BOOL pageControlUsed;
}
//...
#end
What is the <UIScrollViewDelegate> for?
How does it work and why is it used?
<UIScrollViewDelegate> is saying that the class conforms to the UIScrollViewDelegate protocol.
What this really means is that the class must implement all of the required methods defined within the UIScrollViewDelegate protocol. Simple as that.
You can conform your class to multiple protocols if you like:
#implementation MyClass : UIViewController <SomeProtocol, SomeOtherProtocol>
The purpose of conforming a class to a protocol is to a) declare the type as a conformant of the protocol, so you can now categorize this type under id <SomeProtocol>, which is better for delegate objects that objects of this class may belong to, and b) It tells the compiler to not warn you that the implemented methods are not declared in the header file, because your class conforms to the protocol.
Here's an example:
Printable.h
#protocol Printable
- (void) print:(Printer *) printer;
#end
Document.h
#import "Printable.h"
#interface Document : NSObject <Printable> {
//ivars omitted for brevity, there are sure to be many of these :)
}
#end
Document.m
#implementation Document
//probably tons of code here..
#pragma mark Printable methods
- (void) print: (Printer *) printer {
//do awesome print job stuff here...
}
#end
You could then have multiple objects that conform to the Printable protocol, which could then be used as an instance variable in, say, a PrintJob object:
#interface PrintJob : NSObject {
id <Printable> target;
Printer *printer;
}
#property (nonatomic, retain) id <Printable> target;
- (id) initWithPrinter:(Printer *) print;
- (void) start;
#end
#implementation PrintJob
#synthesize target;
- (id) initWithPrinter:(Printer *) print andTarget:(id<Printable>) targ {
if((self = [super init])) {
printer = print;
self.target = targ;
}
return self;
}
- (void) start {
[target print:printer]; //invoke print on the target, which we know conforms to Printable
}
- (void) dealloc {
[target release];
[super dealloc];
}
#end
I think you need to understand the Delegate Pattern. It is a core pattern used by iphone/ipad applications and if you don't understand it you will not get far. The link to wikipedia I just used outlines the pattern and gives examples of it's use including Objective C. That would be a good place to get started. Also look at take a look at the Overview tutorial from Apple which is specific to the iPhone and also discusses the Delegate pattern.