How to use enum in init method? - objective-c

I have the following code which has an init method that takes an enum as an attribute, but I'm getting an error for an elected identifier.
typedef NS_ENUM(NSUInteger, ActivtyLevel) {
kActivityLevelSedentary,
kActivityLevelLight,
kActivityLevelModerate,
kActivityLevelHeavy,
kActivityLevelExtreme
};
#interface DFUserProfile ()
#property (nonatomic, strong) NSNumber *weight;
#property (nonatomic, strong) NSNumber *bodyFatPercentage;
#end
#implementation DFUserProfile
- (id)initWithWeight:(NSNumber *)iWeight bodyFat:(NSNumber *)iBodyFat andActivityLevel:(NSUInteger)iActivtyLevel {
if (self = [super init]) {
_weight = iWeight;
_bodyFatPercentage = iBodyFat;
ActivtyLevel = iActivtyLevel;
}
return self;
}
#end

The typedef declares a type called ActivityLevel, you need a variable or property with that type.
For example you might declare the property:
#property (nonatomic) ActivityLevel activityLevel;
and then declare your method as:
- (id)initWithWeight:(NSNumber *)iWeight
bodyFat:(NSNumber *)iBodyFat
andActivityLevel:(ActivityLevel)iActivtyLevel // note use of the enumeration type
{
...
_activityLevel = iActivityLevel;

You need to have a variable of the type of the enum, you can't store it directly into the enum, that is a type. Add this:
#property (nonatomic) ActivityLevel activityLevel;
then in your init method:
_activtyLevel = iActivtyLevel;

Related

Assigning NSNotFound to a property?

Can I assign 'NSNotFound' to a property of type NSInteger? So here is what I have:
#interfcae MyClass()
#property (nonatomic) NSInteger sectionNumber;
#end
#implementation MyClass
- (id)init
{
[my_switch isOn] ? self.sectionNumber = 0 : self.sectionNumber = NSNotFound;
}
#end
This throws an error saying "Assignment to readonly property". Even if I just try "self.sectionNumber = NSNotFound", I get the same error.
Can I not assign NSNotFound to a property? If not what could be the other options I have?
Your code should be:
- (id)init {
self.sectionNumber = [my_switch isOn] ? 0 : NSNotFound;
}
And Wain makes a good point about this init method. Either rename this to something other than init or make this a proper init method.
Update:
Based on your comment you have the following in the .h:
#property (nonatomic, readonly) NSInteger sectionNumber;
This means in the .m you need:
#property (nonatomic, readwrite) NSInteger sectionNumber;

Objective-C Where to define initial Class Properties

just wanted to ask where I define initial class properties?
From other languages I am used to define some standard properties in the head before the content of the class starts.
For example paths to files. Settings and so on.
Where I fill these initial properties with values in Objective-C?
Thanks
Generally it's something like:
MyClass.h:
extern NSString * const staticValue1;
extern NSString * const staticValue2;
#interface MyClass : NSObject
{
NSString *_strval;
int _intval;
float _fltval;
}
#property (retain, nonatomic, readwrite) NSString *strval;
#property (assign, nonatomic, readwrite) int intval;
#property (assign, nonatomic, readwrite) float fltval;
#end
MyClass.m:
NSString * const staticValue1 = #"Something";
NSString * const staticValue2 = #"Something else";
#interface MyClass
#synthesize strval = _strval;
#synthesize intval = _intval;
#synthesize fltval = _fltval;
- (id)init
{
self = [super init];
if (self != nil)
{
[self setStrval:[NSString stringWithFormat:#"This is a %#", #"string"]];
[self setIntval:10];
[self setFltval:123.45f];
}
return self;
}
- (void)dealloc
{
[self setStrval:nil];
[super dealloc];
}
#end
This demonstrates the use of synthesized properties which are being used here to manage the memory of the instance variable _strval, which requires retaining/releasing to avoid memory leaks. Note that [self setStrval] is initialised with an autoreleased object (from [NSString stringWithFormat) and will be retained by the setter method. Alternatively these methods can be called using the following syntax, if you prefer:
self.strval = [NSString stringWithFormat:#"This is a %#", #"string"];
self.intval = 10;
self.fltval = 123.45f;
Maybe some of what you are after can be implemented with class methods.
Class methods are coded with a + (instead of the instance methods' -), and can't refer to instance variables, as they are not associated with any specific instance of the class.
This is a class method to return a default string:
+ (NSString *)myDefaultString
{
return #"Some default value";
}
You call it by simply calling it with the class name at the receiver's place. Imagine you have defined the method in a class called MyClass, the you call it like this:
NSString *str = [MyClass myDefaultString];
You'll notice that there is no alloc/init calls in this.
Public property needs to be define in .h file.
#interface MyClass {
}
#property(nonatomic, reatin) NSString *a;//Define as per needs, then synthesise in .m file
#end
For private property you need define inline category in .m file-
#interface MyClass ()
#property(nonatomic, reatin) NSString *b;//Define as per needs, then synthesise in .m file
#end
#implementation MyClass
#synthesize a = _a;
#synthesize b = _b;
- (void)viewDidLoad {
//You can initialise property here or in init method
self.a = #"Demo1";
self.b = #"Demo2";
}
//Now you can have other code for this class.
#end

Synthesize property to a Base class' ivar

I have a hierarchy of model objects which I will be displaying on different type of UITableViewCell subclasses. All decision is made on the fly as to which model object should be used and corresponding UITableViewCell subclass' object is spawned and then set the model object to the UITableViewCell's subclass object so that it can fetch values from it.
My UITableViewCell hierarchy is something like this:
The base class Cell hierarchy:
#interface BaseCell : UITableViewCell
{
Base *baseObj_;
}
#end
The subclass of cell hierarchy:
#interface DerivedCell : BaseCell
{
}
#property (nonatomic, retain) Derived *derivedObject;
#end
#implementation DerivedCell
#synthesize derivedObject = baseObj_;
#end
The base class of Model object:
#interface Base : NSObject
{
NSString *title_;
}
#property (nonatomic, retain) NSString *title;
#end
The subclass of model hierarchy
#interface Derived : Base
{
NSString *detailedText_;
}
#property (nonatomic, retain) NSString *detailedText;
#end
When I do so, I am having errors in this line:
#synthesize derivedObject = baseObj_;
Which reads:
Property 'derivedObject' attempting to use ivar 'baseObj_' declared in super class BaseCell.
Type of property 'derivedObject' (Derived*) does not match type of ivar 'baseObj_' ('Base * __strong')
I want to use properties and synthesize them so that I can leverage the uses of properties (like using dot notation etc.). I have for now used accessors and setters which solves the problem:
#interface DerivedCell : BaseCell
{
}
-(Derived*)derivedObject;
-(void)setDerivedObject:(Derived*)newDerivedObject;
#end
But I was just wondering if I could somehow fix these errors to use the properties only.
Thanks,
Raj
Try the below code I have modified your code a bit as shown below
Since you can assign class Base object to class Derived in #synthesize, it can be achieved by this way, I know you have tried it already, I have tried it with the below code and able to access the variables with dot, try the below code and let me know if it is not working
#interface DerivedCell : BaseCell
{
Derived *derivedObject;
}
#property (nonatomic, retain) Derived *derivedObject;
#end
#implementation DerivedCell
#dynamic derivedObject;
- (void)setDerivedObject:(Base *)baseObj {
if (self.derivedObject == nil) {
derivedObject = [[Derived alloc] init];
}
derivedObject.detailedText = baseObj.title;
}
- (Derived *)derivedObject {
return derivedObject;
}
#interface Derived : Base
{
NSString *detailedText_;
}
#property (nonatomic, retain) NSString *detailedText;
#end
#implementation Derived
#synthesize detailedText = detailedText_;
#end
#interface BaseCell : UITableViewCell
{
Base *baseObj_;
}
#property (nonatomic, retain) Base *baseObj;
#end
#implementation BaseCell
#synthesize baseObj = baseObj_;
#end
#interface Base : NSObject
{
NSString *title_;
}
#property (nonatomic, retain) NSString *title;
#end
#implementation Base
#synthesize title = title_;
#end
Base *b = [[Base alloc] init];
b.title = #"Hello Raj";
BaseCell *bc = [[BaseCell alloc] init];
bc.baseObj = b;
DerivedCell *dc = [[DerivedCell alloc] init];
dc.derivedObject = b;
NSLog(#"Derive dc %#", dc.derivedObject.detailedText);
Another Solution which I have provided has an issue when I checked it
#interface BaseCell : UITableViewCell
{
NSString *baseTitle_;
}
#property (nonatomic, retain) NSString *baseTitle;
#end
#implementation BaseCell
#synthesize baseTitle = baseTitle_;
#end
#interface DerivedCell : BaseCell
{
NSString *derivedTitle_;
}
#property (nonatomic, retain) NSString *derivedTitle;
#implementation DerivedCell
#synthesize derivedTitle = baseTitle;
#end
When I created instance for the class and as shown below
DerivedCell *dCell = [[DerivedCell alloc] init];
dCell.baseTitle = #"Hello";
NSLog(#"%#",dCell.baseTitle);//Output was Hello
NSLog(#"%#",dCell.derivedTitle);//Output was (null)
It didn't assign the value to derivedTitle, If it is working for you please let me know
Another solution with memory referncing
#interface BaseCell : UITableViewCell
{
NSMutableString *baseTitle_;
}
#property (nonatomic, retain) NSMutableString *baseTitle;
#end
#implementation BaseCell
#synthesize baseTitle = baseTitle_;
#end
#interface DerivedCell : BaseCell
{
}
#property (nonatomic, retain) NSMutableString *derivedTitle;
#end
#implementation DerivedCell
#synthesize derivedTitle;
- (id) init
{
if ( self = [super init] )
{
baseTitle_ = [[NSMutableString alloc] init];
derivedTitle = baseTitle_;
}
return self;
}
#end
DerivedCell *dCell = [[DerivedCell alloc] init];
[dCell.baseTitle appendString:#"Hello"];
NSLog(#"baseTitle : %#",dCell.baseTitle);
NSLog(#"derivedTitle :%#",dCell.derivedTitle);
Console Output baseTitle : Hello derivedTitle :Hello
One pattern I've used for situations like this is to re-declare the property in a category on the derived class. The one structural change this approach requires from the code you posted is that it requires a same-named property (or equivalent getter/setter methods) to be defined in the base class. Consider the following snippet:
#interface BaseModel : NSObject
#end
#interface DerivedModel : BaseModel
#end
#interface BaseCell : UITableViewCell
{
BaseModel *baseObj_;
}
#property (nonatomic, retain) BaseModel *modelObject;
#end
#interface DerivedCell : BaseCell
#end
#interface DerivedCell (DowntypedPropertyCategory)
#property (nonatomic, retain) DerivedModel *modelObject;
#end
#implementation BaseModel
#end
#implementation DerivedModel
#end
#implementation BaseCell
#synthesize modelObject = baseObj_;
#end
#implementation DerivedCell
#end
In this pattern, the base class declares the iVar and the base-typed property, and synthesizes the implementation. The derived class declares the downcast-typed property in a category. Being in a category, the compiler won't force you to implement methods for that property. This gets you out of trying to synthesize against a superclass's iVar, instead relying on implementations that exist in the superclass, but declaring them to be of a different type. At runtime, the runtime will just end up calling the superclass methods (since Obj-C method dispatch is based on selector only, and does not have multiple dispatch.) As a result, clients of these properties can do stuff like this without any compile time warnings or errors:
#interface UnrelatedObject : NSObject
#end
#implementation UnrelatedObject
- (void)unrelatedMethod: (DerivedCell*)dc
{
DerivedModel* dm = dc.modelObject;
NSLog(#"dm: %#", dm);
}
#end
Again, the catch/minor difference is that in order for this to work, the base class must define a property of the same name (or equivalent getter/setter methods). That said, the property/methods in the base class could be declared (or in the case of methods, NOT even delayed) and defined in the base class's implementation file only, and thus would not be visible to other files merely including the header.
One other note: by using this approach you're missing out on compile time checks for things like mismatch between the property specifiers ([nonatomic|atomic], [readonly|readwrite], [assign|retain|copy]). I've found this pattern incredibly useful, but there are some potential pitfalls to keep an eye out for.
I hope I understand the question correctly, how about typing the model as id?
#interface BaseCell : UITableViewCell
#property(retain, nonatomic) id model;
#end
#implementation BaseCell
#synthesize model;
#end
Then the derived cells can use whatever model classes they want.
When you initialize an instance variable through synthesize, that variable is not accesible from any class that may inherit it.
It looks like you may have been trying to point synthesize to a public instance variable and I'm not sure if that is possible. It may be trying to declare a new variable with the same name which I'm sure would generate some compiler warnings at the least since that new declaration would hide an existing one and is less accessible.
You could simply write your own getter and setter to expose the instance variable.
- (Base *) baseObj {
return _baseObj;
}
- (void) setBaseObj:(Base *)val {
if( val != _baseObj ) {
[_baseObj release];
_baseObj = [val retain];
}
}
Hope this helps!

In Objective-C, how do I pass a property as an argument for a function and then call the setter/getter methods?

The code is probably the best way to see what I am trying to do:
AcInfo.h:
#interface AcInfo : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString *registrationNumber;
#end
AcInfo.m:
#implementation AcInfo
#dynamic registrationNumber;
#end
AnotherClass.h:
#interface AnotherClass : NSObject {
}
#property (nonatomic, retain) AcInfo *detailItem;
#property (nonatomic, retain) IBOutlet UITextField *registrationNumberTextField;
- (void)setDetailItemValueFromUIElement:(id *)uiElement forAcInfoTarget:(id *)acInfoTarget;
#end
AnotherClass.m:
#import "AcInfo.h"
#implementation AnotherClass
#synthesize detailItem, registrationNumberTextField;
- (void)viewDidLoad
{
[super viewDidLoad];
registrationNumberTextField.text = #"Test";
// I expect this to set detailItem.registrationNumber to the value of
// registrationNumberTextField.text (Test) but it doesn't change anything!
setDetailItemValueFromUIElement:registrationNumberTextField forAcInfoTarget:detailItem.registrationNumber;
}
- (void)setDetailItemValueFromUIElement:(id *)uiElement forAcInfoTarget:(id *)acInfoTarget
{
if ([(id)uiElement isKindOfClass:[UITextField class]]) {
// This doesn't do anything when it returns!
(NSString *)acInfoTarget = (UITextField *)uiElement.text
return;
}
}
#end
In short, I want acInfoTarget to call the getter [detailObject registrationNumber] and the setter [detailObject setRegistrationNumber] in the setDetailItemValueFromUIElement: function...
You can set or read properties by name using
// setter
NSString *propertyName = #"myProperty";
[object setValue:newValue forKey:propertyName];
// getter
id value = [object valueForKey:propertyName];
This is slower than using the normal dot notation, though, and it's frequently (though not always) a sign of poorly-designed code.
Also note that id is a pointer type, so you probably don't actually mean "(id*)".
Your code wants to look something like this, I think:
- (void)setDetailItemValueFromUIElement:(id)uiElement forAcInfoTarget:(NSString*)acInfoTarget {
if ([(id)uiElement isKindOfClass:[UITextField class]]) {
NSString *newValue = ((UITextField*)uiElement).text;
[self.detailItem setValue:newValue forKey:acInfoTarget];
}
}
Properties are just syntax sugar for a couple of accessor methods. They are not, in essence, variables so you shouldn't treat them as such. If you want to affect a property, then what you wanting to do is call a method. So you should pass a id and selector parameter and not pointer to a variable type.

Objective-C property that is readonly publicly, but has a private setter

I'd like to use the #property syntax to declare a synthesized property that is publicly readonly but has a setter that can be called privately from within the class.
Since it's Objective-C, this basically means that the setFoo: method would be synthesized, but calling it outside of the class itself would result in a warning (unrecognized selector). To trigger the warning I have to declare the property readonly; is there any way to force a synthesized setter that is only available within the class?
I think what you're looking for are called class extensions. You would declare the property read-only in the header:
#interface MyClass : NSObject {
}
#property (readonly, assign) NSInteger myInteger;
#end
Then redeclare in your class extension in the implementation file:
#interface MyClass ()
#property (readwrite, assign) NSInteger myInteger;
#end
#implementation MyClass
#end
For more check out Apple's documentation
I might be late, but without extension i did using the following technique
#interface MyClass : NSObject {
NSString * name;
}
#property (readonly, strong) NSString * name;
#end
on the other hand in implementation file
#implementation MyClass
#synthesize name;
- (id)initWithItems:(NSDictionary *)items {
self = [super init];
if(self)
{
name = #"abc";
}
return self;
}
#end
doing so it will set your value and will be accessible as readonly.
Thanks.

Categories