Incomplete Implementation Example Help! - objective-c

I am working on an example from a book that I got and it doesnt seem to be working I am getting the warning Incomplete implementation. When I run the program I get an error singal "EXC_BAD_ACCESS". The warning is in the .m file at the line return [NSString stringWithFormat:#"Name:... Does anyone know what I am doing wrong?
my .m file
#import "RadioStation.h"
#implementation RadioStation
+ (double)minAMFrequency {
return 520.0;
}
+ (double)maxAMFrequency {
return 1610.0;
}
+ (double)minFMFrequency {
return 88.3;
}
+ (double)maxFMFrequency {
return 107.9;
}
- (id)initWithName:(NSString *)newName atFrequency:(double)newFreq atBand:(char)newBand {
self = [super init];
if (self != nil) {
name = [newName retain];
frequency = newFreq;
band = newBand;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:#"Name: %#, Frequency: %.1f Band: %#", name, frequency, band];
}
- (void)dealloc {
[name release];
[super dealloc];
}
#end
My .h file
#import <Cocoa/Cocoa.h>
#interface RadioStation : NSObject {
NSString *name;
double frequency;
char band;
}
+ (double)minAMFrequency;
+ (double)maxAMFrequency;
+ (double)minFMFrequency;
+ (double)maxFMFrequency;
-(id)initWithName:(NSString*)name
atFrequency:(double)freq
atBand:(char)ban;
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
#end
radiosimulation.m file:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
NSMutableDictionary* stations = [[NSMutableDictionary alloc] init];
RadioStation* newStation;
newStation = [[RadioStation alloc] initWithName:#"Star 94"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WSTR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WSTR"]);
newStation = [[RadioStation alloc] initWithName:#"Rocky 99"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WKFR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WKFR"]);
[stations release];
[pool drain];
return 0;

You are declaring the following property accessor/mutators (getter/setters) but are not implementing them in your .m file.
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
You need to implement all 6 of these methods in the .m file if you want to remove the warning about incomplete implementation.
You are effectively saying in the .h file that this is what your object is going to do, then not doing it in the .m. It won't generate an error, as objective-c messaging means that the message will be handed up to NSObject to deal with, which will also not have any matching implementation, and the messages will just be silently ignored. I don't like the way that this is only shown as a warning - but there you go.
That said, I wouldn't create the properties like this (there are neater ways of doing this in objective-c using #property), I would remove those method declarations in the .h and replace them with:
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) double frequency;
#property (nonatomic, assign) char band;
These property declarations go in the same place as method declarations.
and then add the following to the .m file:
#synthesize name;
#synthesize frequency;
#synthesize band;
This will avoid having to write all that boilerplate accessor/mutator code that you are currently missing. Again, these go in the same region of the code as method implementations. Effectively the compiler is going to create name and setName methods automatically.
This code is untested - but should point you in the right direction for tidying up the incomplete implementation. It may fix your access error too - but that may require more detailed look at a stack trace.
Another point I'm not sure the code as written even needs to use get/set methods or properties. You might try removing the method declarations from the .h and see if it works. It seems that all the accesses to name, frequency and band are all from within the object.

Related

App crashing while working with class and not going to catch

In my AppDelegate.m, I am doing something like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#try {
// initalizing Meeting config
MeetingConfig *config = [[MeetingConfig alloc] init];
NSLog(#"Initalized Meeting Config: %#", config);
[config setRoomName:#"test123"];
NSLog(#"SetRoom name for Meeting config: %#", config.roomName);
NSString *clientId = #"";
NSLog(#"Unused Client id is: %#", clientId);
//Call UIView from here
}#catch (NSException *exception) {
NSLog(#"exception: %#", exception);
}
return YES;
}
Where my MeetingConfig.m file looks like this
#implementation MeetingConfig
- (id) init
{
if (self = [super init]) {
self.apiBase = #"https://api.in";
self.showSetupScreen = false;
self.autoTune = true;
}
return self;
}
- (void) setAuthToken:(NSString *)authToken
{
self.authToken = authToken;
}
- (void) setApiBase:(NSString *)apiBase
{
self.apiBase = apiBase;
}
// more code
and MeetingConfig looks like this
#import <Foundation/Foundation.h>
#interface MeetingConfig : NSObject
#property (nonatomic, assign) NSString* roomName;
#property (nonatomic, assign) NSString* authToken;
#property (nonatomic, assign)Boolean autoTune;
#property (nonatomic, assign)NSString* apiBase;
#property (nonatomic, assign)Boolean showSetupScreen;
- (void) setRoomName:(NSString *)roomName;
- (void) setAuthToken:(NSString *)authToken;
- (void) setShowSetupScreen:(Boolean)showSetupScreen;
- (void) setAutoTuneEnabled:(Boolean)autoTune;
- (id) init;
#end
Can someone help me in determining what I could be doing wrong here? and why doesn't it log exception in NSLog? Also, I am super new to objective C (i have been asked to stick with Objective c) and if anyone have any suggestion in regards to the code then please let me know.
Error
You're using assign for reference/pointer types: #property retain, assign, copy, nonatomic in Objective-C
They should probably be declared copy, because this is a kind of value object, I think.
No exceptions were caught because no exceptions were thrown. Throwing/catching exceptions for control flow is not common in Objective-C
You don't need to write explicit setter functions for #properties
You should prefer to use BOOL type instead of Boolean, with values of YES/NO instead of true/false.
You should return instancetype not id from init, at least in reasonably modern Objective C
Consider making an initialiser that takes all the properties (initWithRoomName:clientID:) and make them read only once set
You don't need to declare -(id) init in your header since it gets that from NSObject

How can I pass a NSString parameter to a function?

I want to initialize an object. The problem is how to pass the NSString correctly.
Object code:
#import "ClaseHoja.h"
#implementation ClaseHoja
#synthesize pares;
#synthesize nombre;
-(id)init
{
self=[super init];
if(self){
}
return self;
}
-(id)initWithValues:(NSString*)nom par:(int)par
{
if([super init]){
pares=par;
nombre=nom;
}
return self;
}
When I call the function I do this:
NSString *nombre="Hello";
int par=20;
ClaseHoja *ch = [ClaseHoja alloc] initWithValues:nombre par:numPares]];
I would suggest:
Add the missing # to #"Hello" and fix the [] in your alloc/init call.
If you're using Xcode, I'd let the compiler synthesize the properties for you. No #synthesize is needed. If you're using a stand-alone LLVM on some other platform, though, you might need it, but by convention, you'd specify an ivar with a preceding _.
I'd define nombre to be copy property and explicitly copy the nombre value passed to your init method. You don't want to risk having a NSMutableString being passed to your method and having it unwittingly mutated without your knowledge.
I'd suggest renaming the initWithValues:par: to be initWithNombre:pares:, to eliminate any doubt about what properties are being updated.
You don't need init without parameters. You can just rely on the one provided by NSObject.
You'd generally use NSInteger rather than int.
In your custom init method, you want to make sure to do if ((self = [super init])) { ... }
Thus:
// ClaseHoja.h
#import Foundation;
#interface ClaseHora: NSObject
#property (nonatomic, copy) NSString *nombre;
#property (nonatomic) NSInteger pares;
- (id)initWithNombre:(NSString*)nombre pares:(NSInteger)pares;
#end
And
// ClaseHoja.m
#import "ClaseHoja.h"
#implementation ClaseHoja
// If you're using modern Objective-C compiler (such as included with Xcode),
// you don't need these lines, but if you're using, for example stand-alone
// LLVM in Windows, you might have to uncomment the following lines:
//
// #synthesize nombre = _nombre;
// #synthesize pares = _pares;
- (id)initWithNombre:(NSString*)nombre pares:(NSInteger)pares {
if ((self = [super init])) {
_pares = pares;
_nombre = [nombre copy];
}
return self;
}
#end
And you'd use it like so:
NSString *nombre = #"Hello";
NSInteger pares = 20;
ClaseHoja *ch = [[ClaseHoja alloc] initWithNombre:nombre pares:pares];
You need to pass like this. Another thing you miss # sign before the string.
NSString *nombre = #"Hello"; int par=20;
ClaseHoja *ch = [[ClaseHoja alloc]initWithValues:nombre par:par];

Cocoa Console Application - property not found on object of type

So I am quite new on OC programming, I come from Front-end background (i.e. HTML/CSS/JavaScript ...), so I understand basic concepts of programming :)
Basically I created a console application, with a simple FooClass.
FooClass.h
#import <Foundation/Foundation.h>
#interface FooClass : NSObject
#property (strong, nonatomic) NSString *username;
- (NSString *) username;
- (void) setUsername:(NSString *)username;
#end
FooClass.m
#import "FooClass.h"
#implementation FooClass
#synthesize username = _username;
- (instancetype) init
{
self = [super init];
if (self) {
}
return self;
}
- (NSString *) username
{
return _username;
}
- (void) setUsername:(NSString *)username
{
_username = username;
}
#end
And in the main.m file, where the app bootstraps.
#import <Foundation/Foundation.h>
#include "FooClass.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
FooClass *foo = [[FooClass alloc] init];
foo.username = #"a";
}
return 0;
}
XCode tells me that it cannot find property username on object of type FooClass. And I don't really have idea about it. Any one could help?
I am a bit late in posting the answer. Here are few things that you should consider.
Since you have a property username. You are not required to create methods for setters and getters. The compiler will create them for you. Simply remove the two statements.
No need to synthesize in .m as well.
Instead of #include use #import. import takes only one copy even if you try to add the file(s) directly or indirectly from other files as compared to include.

"Expected a type" error Objective C

I've asked questions on here so many times about this ruddy game that I'm trying to make. I'm working on a Text-Based adventure game. First I made it in Java because that's what I was learning the the class the game was for. Now I'm trying to learn iOS development which requires objective-c. I feel pretty comfortable with objective c after taking the Lynda Essentials course (The previous experience with Java helped of course). Anyways I'm working on this game and I'm running into a problem that seems pretty unique to objective c.
In Java when I have multiple classes they just need to be in the same directory in order for me to use them in other classes. This is not the case in Objective-C... I have to import the header files if I want to use class A in class B. Well for this game I have two custom classes, a Location class and an Exit class. The Location class needs to know about what Exits it has (So I have to import Exit.h if I want to use them) and the exits need to know which location it's connected to (So I have to import Location.h). It seems that I can't do this because of something called Circular Referencing (or something like that). However, if I don't do this then I get an "Expected a type" error. So I have no idea what to do. I'll show the code below.
Exit.h
#import <Foundation/Foundation.h>
#import "Location.h"
#define NORTH 0
#define SOUTH 1
#define EAST 2
#define WEST 3
#interface Exit : NSObject
#property NSString * dirName;
#property NSString * dirShortName;
#property int direction;
#property Location * connection;
-(id)initWithConnection:(Location *) loc andDirection:(int) dir;
#end
Exit.m
#import "Exit.h"
#implementation Exit
#synthesize dirName;
#synthesize dirShortName;
#synthesize direction;
#synthesize connection;
-(id)initWithConnection:(Location *)loc andDirection:(int)dir {
self = [super init];
if(self) {
direction = dir;
switch(direction) {
case 0:
dirName = #"North";
dirShortName = #"N";
break;
case 1:
dirName = #"South";
dirShortName = #"S";
break;
case 2:
dirName = #"East";
dirShortName = #"E";
break;
case 3:
dirName = #"West";
dirShortName = #"W";
break;
}
connection = loc;
}
return self;
}
#end
Location.h
#import <Foundation/Foundation.h>
#interface Location : NSObject
#property NSString * title;
#property NSString * desc;
#property NSMutableDictionary * exits;
#property BOOL final;
-(id) initWithTitle:(NSString *) _title;
-(id) initWithDescription:(NSString *) _desc;
-(id) initWithTitle:(NSString *) _title andDescription:(NSString *) _desc;
-(void) addExit:(Exit *) _exit;
#end
Location.m
#import "Location.h"
#implementation Location
#synthesize title;
#synthesize desc;
#synthesize exits;
#synthesize final;
-(void) addExit:(Exit *) _exit {
NSString * tmpName = [_exit dirName];
NSString * tmpShortName = [_exit dirShortName];
[exits setObject:tmpName forKey:tmpShortName];
}
-(NSString *)description {
NSString * tmp = [[NSString alloc] initWithFormat:#"%#\n%#\n",self.title,self.desc];
for(NSString * s in exits) {
[tmp stringByAppendingFormat:#"\n%#",s];
}
return tmp;
}
// Initialization Methods
-(id) init {
self = [super init];
if(self) {
title = #"";
desc = #"";
}
return self;
}
-(id) initWithTitle:(NSString *) _title {
self = [super init];
if(self) {
title = title;
desc = #"";
exits = [[NSMutableDictionary alloc] initWithObjectsAndKeys:nil];
}
return self;
}
-(id) initWithDescription:(NSString *) _desc {
self = [super init];
if(self) {
title = #"";
desc = desc;
exits = [[NSMutableDictionary alloc] initWithObjectsAndKeys:nil];
}
return self;
}
-(id)initWithTitle:(NSString *) _title andDescription:(NSString *)_desc {
self = [super init];
if(self) {
title = title;
desc = desc;
exits = [[NSMutableDictionary alloc] initWithObjectsAndKeys:nil];
}
return self;
}
#end
I'm really hoping I'm not trying to do something that's impossible. I also hope my code can be made sense of and I'm not making too much of a fool of myself here ;) thanks for any advice.
EDIT:
Just reread and now understand better, you need to do #class Exit; to define the Exit class in the Location header and then you can do the same #class Location; in the Exit header in order to tell the compiler that the classes are defined. Then if you were to reference those classes in the implementation files (.m) then you would import the Exit.h file and Location.h file respectively
The rule of thumb I have started to follow, which seemed counter-intuitive to me at first is this:
In your header files, use "forward declarations" prolifically with only 2 exceptions:
headers for classes you are extending, and headers for protocols you are conforming to; and only do #import directives in your .m files.
This should resolve the circular reference error; it did mine.
See here, and do a 'find' for the word "forward".

Help with a method that returns a value by running another object's method

I have a Class that runs the following method (a getter):
// the interface
#interface MyClass : NSObject{
NSNumber *myFloatValue;
}
- (double)myFloatValue;
- (void)setMyFloatValue:(float)floatInput;
#end
// the implementation
#implementation
- (MyClass *)init{
if (self = [super init]){
myFloatValue = [[NSNumber alloc] initWithFloat:3.14];
}
return self;
}
// I understand that NSNumbers are non-mutable objects and can't be
// used like variables.
// Hence I decided to make make the getter's implementation like this
- (double)myFloatValue{
return [myFloatValue floatValue];
}
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput;
}
#end
When I mouse over the myFloatValue object during debugging, it does not contain a value. Instead it says: "out of scope".
I would like to be able to make this work without using #property, using something other than NSNumbers, or other major changes since I just want to understand the concepts first. Most importantly, I would like to know what mistake I've apparently made.
I can see a couple of mistakes:
The line #implementation should read #implementation MyClass
The function setMyFloatValue is missing a closing ] and } —it should read:
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput];
}
}
I've just tested it in Xcode and it works for me with these changes.
Why not just set property in interface and synthesize accessors in implementation?
#interface MyClass : NSObject {
float *myFloat
}
#property (assign) float myFloat;
#end
#implementation MyClass
#synthesize myFloat;
#end