Proper way to modify an NSMutableDictionary instance variable? - objective-c

I have an Objective-C NSMutableDictionary declared inside a class's #interface section, with getter/setter methods, like so:
#interface myClass : NSObject
{
NSMutableDictionary *dict;
}
- (void) setDict: (NSMutableDictionary *) newDict;
- (NSMutableDictionary *) dict;
Inside some of my #implementation methods I want to modify dict. I'd like to stick to standard Obj-C idiom and modify it "properly". Is it OK to modify it like this, using the getter but not the setter:
[[self dict] removeObjectForKey:#"myKey"];
...or is there a better way to do this?

That'll work, but why not do:
[dict removeObjectForKey:#"myKey"];
Inside a class's implementation, you have direct access to the instance variables, and using them directly is idiomatic Objective-C.

Related

Custom NSArray Class definition

I try to write my own class in objective-c. I declared a class variable NSArray *_people in it. I set all setters and getters and everything works fine for me but.. A silly easy question. When I want to query my array with a 'for' loop It must go like this:
for (NSString *s in [myClass people])
How do I achieve the same behavior as with a usual NSArray class instance like this?:
for (NSString *s in people)
If you want to keep people array property private, then you should implement NSFastEnumeration protocol in your new class. Custom implementation is quite dificult (buffering, change mutation flag, pointers and size), but your case it is pretty simple.
In your .m file you should implement:
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len {
return [self.people countByEnumeratingWithState:state objects:buffer count:len];
}
And in your header file:
#interface YourClass : NSObject<NSFastEnumeration>
MyClass.h
#interface MyClass
#property (nonatomic, strong) NSArray *people;
#end
Now, you can access the array like...
for(NSString *s in [myclass people])

Get pointer to array held in super class

Studying polymorphism in objective c . I'm trying to do some things using an NSMutableArray that is held by my super class, so I need a pointer to it from the sub class.
SuperViewController.h
#interface SuperViewController : UIViewController
- (NSMutableArray *) myArray;
#end
SuperViewController.m
#interface SuperViewController()
#property (strong, nonatomic) NSMutableArray *myArray;
#end
#implementation SuperViewController
- (NSMutableArray *) myArray {return self.myArray;}
#end
Then, in my subclass, I have this:
SubViewController.h
#import SuperViewController.h
#interface SubViewController : SuperViewController
- (void) updateUI;
#end
SubViewController.m
#implementation
- (void) updateUI
{
(NSMutableArray *) myArray = [super myArray];
}
#end
It crashes the App . I've tried quite a few different approaches, but I always wind up crashing. Can anyone help me out? Thanks!
The reason is, that you have a recursion which blows the stack:
- (NSMutableArray *) myArray
{
return self.myArray;
}
This method calls itself. The dot notation is a short form of method invocation:
- (NSMutableArray *) myArray
{
return [self myArray];
}
It is not an access to the object's context (ivar) as you probably expected:
- (NSMutableArray *) myArray
{
return self->_myArray;
}
The right way is to use the ivar directly:
- (NSMutableArray *) myArray
{
return _myArray;
}
BTW:
Properties can have the readonly attribute.
Using super in the derived class is useless and dangerous. It does not use the super's context (which does not exist, because every instance object has only one context built from the whole class hierarchy), but uses the super implementation of the method. You did not overwrite this implementation in the derived class. self would work, too, and gives you the ability to overwrite the getter.
You've written self.myArray to access an instance variable. The dot notation is a property access, and will invoke a property-like method even if not declared as a property. In your case this means your attempt to access the instance variable is in fact a self-recursive call, which will result in stack overflow.
To access an instance variable either use just it's name or the -> member access operator, e.g. _myArray or self->_myArray.

Working between classes Objective C

I have a basic question about working with classes in objective-c and maybe just programming in general. I would like to use a variable declared in my class Signup.h in another class, Exittext.m. When I include "Signup.h" in my .m file and try to use the variable, it doesn't know what it is. Is this because they are private? Is there a way to do this or can I only use variables declared in that particular class?
#interface SignupView : UIViewController
NSMutableArray *textfields;
}
#implementation Exittextfields
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textfields resignFirstResponder];
return YES;
}
In traditional OO programming, accessing a variable in another class involves manually writing getter and accessor methods to expose/modify a "private" variable. In Objective-C, properties (instance variables declared with #property) takes care of generating those getters and setters automatically.
Check out this great tutorial by Ray Wenderlich.
So in your case, you'll need to declare the mutable array you want to be accessed by other classes in the .h file as a property.
Example:
#property (nonatomic, strong) NSMutableArray *myArray;
Now when a new instance of Signup is called, the array myArray can be properly accessed using either a traditional getter method or dot syntax.
Example:
Signup *sign = [[Signup alloc] init];
[sign myArray];
//OR
sign.myArray;

Objective-C: What is the difference between + and - in getters and setters?

What is the difference of using:
+ (id) myMethod;
// Rather than
- (id) myMethod;
Using a + declares the method as a class method, or a method that can be called directly on the class, where the class is the object. So when you have this:
#implementation Foo
+(NSString*)method1 {
return #"Foo";
}
-(NSString*)method2 {
return #"Foo";
}
#end
The methods are called in different ways:
[Foo method1]; //=> #"Foo"
Foo* f=[[Foo alloc] init];
[f method2]; //=> #"Foo"
One other thing to note is that class methods don't have access to an instance, which means they can't access any kind of instance variables.
#Linuxios pretty much summed up the concept of class and instance method. However, since you mentioned getters and setters in your title, I want to point out that in Objective-C you can use properties instead of writing your own accessor methods. For example,
In the header file, you will have something like this:
#interface MyObject : NSObject
#property (nonatomic,retain) NSSet* mySet;
#end
In the m file, you wil have something like this:
#implement MyObject
#synthesize mySet;
#end
To access the set in another class you can do it like this:
myObject.mySet; // assuming myObject is an instance of the MyObject class
The top one is a class method (no instance required)
The second one is a instance variable (attached to a specific instance).
This answer explains the methods quite well:
Method Syntax in Objective C
[MyObject myMethod]; // did not have to create an instance
MyObject* myNewObject = [[MyObject alloc] init] autorelease];
[myNewObject myMethod]; // had to create an instance

#synthesized properties and KVC

Should setter generated with #synthesize be KVC compilant or not? I found statement that getters and setters generated are KVC-compliant, shouldn't it call one of this methods?
#interface testing : NSObject
#property (nonatomic, retain) NSString *phone;
#end
implementation:
#implementation testing
#synthesize phone;
- (id)init {
self = [super init];
return self;
}
// none of these is called with dot syntax, or setter setPhone
- (void)setValue:(id)value forKey:(NSString *)key
{
NSLog(#"%#",key);
[super setValue:value forKey:key];
}
-(void)setValue:(id)value forKeyPath:(NSString *)keyPath
{
NSLog(#"%#",keyPath);
[super setValue:value forKeyPath:keyPath];
}
#end
and test it with:
testing *t = [[testing alloc] init];
[t setPhone:#"55555555"];
I think you've got it the wrong way round.. KVC compliant doesn't mean that an accessor will call -setValue:forKey: Being KVC compliant means that calling -setValue:forKey: will call the accessor.
Expanding a bit: KVC compliant only means 'follows naming conventions'. Why is this important? I can call my accessor methods anything i like. For a property 'Foo':
- (void)weakSetFoo:(id)f;
- (id)autoreleasedFoo;
This is fine. But a mechanism like Bindings will try to set Foo by calling
[ob setValue:newVal forKey:#"foo"];
-setValue:forKey: will try to do the right thing and use the accessor method (if we wrote a setter method, it's because we want it to be used, right?). But unless we named our setter method the standard -setFoo: there's no way it will be found.
So -weakSetFoo: is a setter method, but the property Foo isn't KVC compliant.
If i change the setter name to -setFoo: the property Foo is now KVC compliant.
Synthesized accessor methods will by default be named correctly.
You don't need to implement setValueForKey: for KVO. It is implemented for you within the framework. By making your properties KVO compliant (which you have done using #property and #synthesize), everything just works 'magically'
----- update
Also, your testing code would not test KVO. To test it, do something like:
testing *t = [[testing alloc] init];
[t setValue:#"55555555" forKey:#"phone"];
It is actually the other way round.
These are setValue:forKey and getValueforKey which look up the KVC-compliant properties, not properties synthesized through them.
When you write #synthesize property the compiler actually just stuffs - (type) property and - (void) setProperty: (type)value kind of methods which read/set corresponding instance variable.