declaring class in controller - objective-c

I'm reading an Objective-C Fundamentals book that's taking me through the construction of a basic app. However, it doesn't always show us what to do. At one point, it says
open RootViewController.h and remove the existing definitions for the PropertyType enumeration and RentalProperty structure. Replace them with the CTRentalProperty class.
Ok, it's easy to find the enumeration and structure it referred to...
typedef enum PropertyType {
Unit,
TownHouse,
Mansion
} PropertyType;
typedef struct {
NSString *address;
PropertyType type;
double weeklyRentalPrice;
} RentalProperty;
but what exactly does it mean (what is the actual code) when it says
Replace them with the CTRentalProperty class
Do I just write
CTRentalProperty;
Probably not. Can you help me understand what the author's talking about. We've made CTRentalProperty.h and CTRentalProperty.m classes/files, but I'm not sure if I'm supposed to copy code from them into the controller.

Probably it means to put
#interface CTRentalProperty : NSObject
{
NSString *address;
PropertyType type;
double weeklyRentalPrice;
}
#end
into CTRentalProperty.h in place of the struct definition. You'll then need to put
#implementation CTRentalProperty
#end
into CTRentalProperty.m.

Not sure about the enum, but the author probably means something like this:
#interface CTRentalProperty : NSObject
#property(nonatomic, strong) NSString *address;
#property(nonatomic, assign) PropertyType type;
#property(nonatomic, assign) double weeklyRentalPrice;
#end

Answering my own question after discovering author provides source code. Although it doesn't seem to make sense given the instructions he provided in the book. Here's what the controller's supposed to look like
#import <UIKit/UIKit.h>
#interface RootViewController : UITableViewController {
NSDictionary *cityMappings;
NSArray *properties;
}
#end

Related

Forward Declaration vs #import when subclassing

I have MyClassA which has a property of type MyClassB
//
// MyClassA.h
//
#interface MyClassA : NSObject
#property (strong, nonatomic, readonly) MyClassB *myClassB;
#end
MyClassB has a property myString.
//
// MyClassB.h
//
#interface MyClassB : NSObject
#property (copy, nonatomic, readonly) NSString *myString;
#end
I have MyClassC which needs to access myString in it's implementation.
Should I -
a) Forward Declare MyClassB in MyClassA.h and #import "MyClassB.h" in MyClassC.m
or
b) #import MyClassB.h in MyClassA.h
In general, you should forward declare with #class where possible in your header files. The only time you probably wouldn't want to do it is when you're inheriting from a super class or declaring protocol conformance, because the compiler needs to know what is going on in that class or protocol.
For this instance, I would use #class for all your property declarations in your header files, and #import MyClassB.h in your MyClassC.m file. That will allow MyClassC to know about all the properties on MyClassB.
Looking at this from a slightly different angle ... you need to decide if you want the world to really know about myClassB being a property of MyClassA. For example, if you may only want to advertise that myString that can be obtained through MyClassA. This insulates other classes from knowing the underlying implementation of myString. Unless you have a need to expose MyClassB you should hide it from the "rest of the world".
In this case you would change MyClassA.h as follows:
//
// MyClassA.h
//
#interface MyClassA : NSObject
#property (strong, nonatomic, readonly) NSString *myString;
#end
In MyClassA.m, you would do the following.
//
// MyClassA.m
//
#import "MyClassA.h"
#import "MyClassB.h"
#interface MyClassA()
#property (strong, nonatomic) MyClassB *myClassB;;
#end
#implementation MyClassA
// Other meaningful code omitted
- (NSString *)myString {
return self.myClassB.myString;
}
#end
Note that what I've done here is use an anonymous category to internally define property for myClassB.
The key thing here is whether or not it makes sense to not expose MyClassB to others. The main advantage of this approach is your code is more malleable. Let's say myString gets derived a different way. From a different class or different method altogether. The code which needs to consume myString is immunized.
If you need to expose MyClassB, then you can either use #class as recommended by Tyler above or #import MyClassB.h from MyClassA.h. Best practices prescribe forward declaring #class. But at times the convenience of not having to remember to import a lot of files within the implementation file can win out. It's your code-base, so you can pick which one works the best for you. I generally use a combination of the two.

Need help trying to use #property in Objective-C

New to Objective-C (and programming for that matter), so please don't be too harsh if this question is very basic.
Apart from my main.m class, I have a Student.h and Student.m class, which I created. I am trying to avoid using many getters and setters for future projects, and if I'm correct, #property can help me with that. My basic code that works is this:
Student.h:
#import <Foundation/Foundation.h>
#interface Student : NSObject{
NSString *name;
int age;
}
//setters
- (void)setName:(NSString*)fName;
- (void)setAge:(int)newAge;
//getters
- (NSString*)getName;
- (int)getAge;
#end
Student.m:
#import "Student.h"
#implementation Student
- (void)setName:(NSString*)fName {
name = fName;
}
- (void)setAge:(int)newAge {
age = newAge;
}
- (NSString*)getName {
return name;
}
- (int)getAge {
return age;
}
#end
Can I use #property to have something like this, which would avoid using getter and setter methods? Or do I understand it all wrong?
#import <Foundation/Foundation.h>
#interface Student : NSObject{
}
#property int age;
#property NSString *name;
#end
Few things:
In Objective C you don't use get prefix for getters. You should use either plain name or with 'is' prefix for boolean properties. (Objective C conventions reference)
You really won't avoid using getters and setters. #property notation just defines them for you (maybe with some additional behaviors like copying the value instead of assigning it). It's just the matter of . notation. Underneath it's using getter/setter methods. Here you have a bit more on properties (Objetive C properties reference).
You should define your NSString property as (copy). It's much better to have as if you change it somewhere else it will affect this object (and probably you want to avoid that).
Are you coming from Java perhaps?
Yes, Objective-C used to require getters and setters to be written out laboriously by hand. Nowadays if you use #property and don't go out of your way to do anything else then a suitable instance variable and an appropriate getter and setter will be generate for you.
So the following is a complete class with usable properties, accessible either via traditional setName:/name-style setters and getters or via the dot notation (which calls the setters and getters despite looking like a C struct access:
#interface Student : NSObject
#property int age;
#property NSString *name;
#end
/* ... */
#implementation Student
#end
Also as a general encapsulation / data-hiding comment, notice that Objective-C has long ago been modified so that instance variables can be declared in the [unpublished] #implementation rather than the [published] #interface. On a technical level it was all to do with the ABI and the fragile base class problem, neither of which haunts the modern runtime.

In Objective-C, why does the variable's type has to be repeated for #property?

For Objective-C, in the following header file:
#interface Peg : NSObject {
char color;
}
#property char color;
I wonder if the member variable is already said to be a char type, then why does the #property has to repeat it? (or else it won't compile). Couldn't the compiler tell that it is char? It couldn't be anything else, could it?
That is because generaly properties don't have to be related to any declared instance variable of your class. You may have a property and not include a variable into your class header. That's why you have to declare it's type.
Using properties instead of variables makes your headers clean, hiding the implementation.
So, you can just declare a property and then #synthesize it
#interface Peg : NSObject
#property char color;
#implementation Peg
#synthesize color;
#end
Actually, it's no longer needed, at least when compiling for x64 with clang. If you omit instance variable, #synthesize will create one for you.
Just use The following
#interface Peg : NSObject {}
#property char color;

"Expected a type" error pointing to the return type of a method

I've attempted to compile, but every time I do, one method throws a strange "expected a type" error. I have a method in the header:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
The error points at the return type for this method. I've imported ANObject into the header using #import "ANObject.h" and ANObject is compiling fine..
Why is this happening?
This is to do with the order that the source files are compiled in. You are already probably aware that you can't call a method before it is defined (see below pseudocode):
var value = someMethod();
function someMethod()
{
...
}
This would cause a compile-time error because someMethod() has not yet been defined. The same is true of classes. Classes are compiled one after the other by the compiler.
So, if you imagine all the classes being put into a giant file before compilation, you might be able to already see the issue. Let's look at the Ship and BoatYard class:
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Once again, because the Ship class has not yet been defined, we can't refer to it yet. Solving this particular problem is pretty simple; change the compilation order and compile. I'm sure you're familliar with this screen in XCode:
But are you aware that you can drag the files up and down in the list? This changes the order that the files will be compiled in. Therefore, just move the Ship class above the BoatYard class, and all is good.
But, what if you don't want to do that, or more importantly, what if there is a circular relationship between the two objects? Let's increase the complexity of that object diagram by adding a reference to the current BoatYard that the Ship is in:
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) BoatYard* currentBoatYard;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Oh dear, now we have a problem. These two can't be compiled side-by-side. We need a way to inform the compiler that the Ship* class really does exist. And this is why the #class keyword is so handy.
To put it in layman's terms, you're saying, "Trust me man, Ship really does exist, and you'll see it really soon". To put it all together:
#class Ship;
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) BoatYard* currentBoatYard;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Now the compiler knows as it compiles BoatYard, that a Ship class definition will soon appear. Of course, if it doesn't, the compilation will still succeed.
All the #class keyword does however is inform the compiler that the class will soon come along. It is not a replacement for #import. You still must import the header file, or you will not have access to any of the class internals:
#class Ship
-(void) example
{
Ship* newShip = [[Ship alloc] init];
}
This cannot work, and will fail with an error message saying that Ship is a forward declaration. Once you #import "Ship.h", then you will be able to create the instance of the object.
I found this error hapenning when there is circular dependency on the headers. Check if the .h file where you declare this method is imported in ANObject.h
You basically add
#class ANObject;
before #interface!
So, for some reason I was getting this error while trying to set a method with an enum type in the parameters. Like so:
- (void)foo:(MyEnumVariable)enumVariable;
I had previously used it like this and never had an issue but now I did. I checked for circular dependency and could find none. I also checked for typos multiple times and no dice. What ended up solving my issue was to adding 'enum' before I wanted to access the variable. Like so:
- (void)foo:(enum MyEnumVariable)enumVariable;
{
enum MyEnumVariable anotherEnumVariable;
}
Usually when I see an error like this it's because I have a typo on a previous line, such as an extra or missing parenthesis or something.
It may sound stupid, but wrong shelling or wrong use of uppercase/lowercase letterwrong case this.
I got this message, when the variable type was misspelled. See below this below
e.g.
-(void)takeSimulatorSafePhotoWithPopoverFrame:(GCRect)popoverFrame {
instead of.....
-(void)takeSimulatorSafePhotoWithPopoverFrame:(CGRect)popoverFrame {
Strangely enough, changing the order of my imports has fixed this in the past... Try moving the import to the bottom after all your other imports.
I solved it by adding #class class_name to the .h file

What are #property and #synthesize used for in Objective-C?

What is the use of #property and #synthesize? Can you explain with an example please?
Really short answer: They create accessors for the ivars.
There are some examples on wikipedia. Look at those.
From the apple developer library:
You can think of a property declaration as being equivalent to declaring two accessor methods. Thus
#property float value;
is equivalent to:
- (float)value;
- (void)setValue:(float)newValue;
And by using #synthesize, the compiler creates accessor methods for you (see more here)
// Sample for #property and #sythesize //
#interface ClassA
NSString *str;
#end
#implementation ClassA
#end
The Main Function main()
//make sure you #import ClassA
ClassA *obj=[[ClassA alloc]init];
obj.str=#"XYZ"; // That time it will give the error that we don't have the getter or setter method. To use string like this we use #property and #sythesize