Key-value observation: Can I observe for changes on ALL properties? - ios

Whenever a property on my object is changed or updated I want to change a variable (nonce variable). This nonce is time-based. So everytime a property is updated this nonce gets updated to the current time.
Is there any way to automatically listen for all key changes on my object? Or will I have to manually maintain all keyvalue observers for each property separately?
Many thanks

Did you take a look at the Obj-C runtime functions? See here in the docs. For example, this gives you a list of all the properties in a class Lender. (BTW: I'm not at my Mac, so this is just straight out of the docs):
#interface Lender : NSObject {
float alone;
}
#property float alone;
#end
you can get the list of properties using:
id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
you can then get the name of a property:
const char *property_getName(objc_property_t property)
If you pipe those names back into addObserver:forKeyPath:options:context you should be golden.

Some ideas:
1) you can ask the runtime for the properties and ivars, and their types, and use that information to create and take down observers. Obviously a lot of work if you are doing this for one object.
2) if your properties are "regular", meaning all strong objects, then you can use #dynamic (to prevent setter/getter creation), then use resolveInstanceMethod: or other funky methods from NSObject to catch setMyObject: and myObject calls. You could in essence do what the system does for 'set...' calls, and dynamically get the string of the variable. You could then update/get an ivar, maybe one that has a prefix of "-" or something, and you'd be able to do what your observers would be doing.
3) You could put all the ivars in a "Helper" class, and direct all the setters to it (which could of course message you back), using forwardingTargetForSelector:. I'm using this technique (sort of) in one of my github projects

Related

Objective-C dynamic implementation

Description + sample + explanation: (You can skip to the question section)
I'd like to make an object instance, which can be implemented by different implementations, depend on a condition (the internet status).
Simple declaration
#interface LoginController : NSObject
/** The currently logged-in User. Nil if not logged-in yet. */
#property (strong, nonatomic) User *currentUser;
// Singleton object
+ (instancetype)shareInstance;
/** Abstract methods, will do nothing if call directly. Use inheritance implements (Online/Offline) instead. */
- (User *)loginByEmail:(NSString *)email password:(NSString *)pwd;
#end
#interface LoginControllerOnline : LoginController
// Login will call request to server.
#end
#interface LoginControllerOffline : LoginController
// Login will check data in coredata.
#end
The LoginController's login method actually do nothing (return nil). Instead, the inherited class (Online/Offline) overwrite the parent login's method, with different implementations (as in comments)
And then, I have a manager to define which class should be in use:
#implement InternetManager
+ (LoginController *)loginController
{
return [self hasInternet] ? [LoginControllerOnline shareInstance] : [LoginControllerOffline shareInstance];
}
+ (BOOL)hasInternet
{
// Check with Reachability.
}
#end
This work. But it's not the mechanism I'd like to achieve.
This mean I have 2 instances of inherited LoginController instead of 1.
When internetStatus change from offline to online, I'd like to re-login online (to get session/oauthToken...). But, I'll have to do many things (copy user, change instance, check retained...) before I can actually call from login online
QUESTION:
Is there a way for me to create only one instance of LoginController, which hold the same properties (User), but can has different (dynamic) implementations (Online/Offline)?
Update question:
Quote from Apple's Dynamic typing:
The isa Pointer:
Every object has an isa instance variable that
identifies the object's class. The runtime uses this pointer to
determine the actual class of the object when it needs to.
So, is there a way for me to change this isa pointer of an object instance?
It sounds like the real problem is that you've given these things direct primary ownership of state that you actually don't want them to own — factor it out. There's no copying, just give each an instance of the thing that marshals sate at -init and allow them to talk to it.
Then just do the normal programming thing when you want to do either one thing or another based on a condition: use an if statement.
So, I don't think use of the dynamic runtime is appropriate. However, academically, supposing an interest:
If you really must, use object_setClass, which "[s]ets the class of an object", answering your actual question. Obviously you need the storage to be compatible, so probably your subclasses shouldn't declare any properties or instance variables.
A commonly-discussed alternative for this general area is not changing the class of an existing instance but changing the methods that are a member of the class. So you'd have two alternative implementations of -loginByEmail:password: and set which was the one that actually responded to that selector dynamically. But there's really no advantage over just using an if if you have access to the source code and a bunch of disadvantages around its generally indirect, opaque nature. The whole thing is usually known as swizzling. class_replaceMethod is the key component but just search for swizzling.

what is the difference between local declarations in objective-c [duplicate]

This question already has answers here:
Is there a difference between an "instance variable" and a "property" in Objective-c?
(6 answers)
Closed 9 years ago.
What is the difference between these declarations, lets call them red and orange:
pros, cons?
The red set is properties, and the orange set is instance variables.
A property declaration tells the compiler to define a getter method, and possibly a setter method. (No setter method if the property is readonly.)
In newer versions of Objective C, declaring a property also creates an instance variable that is used to save values for the property. By convention the instance variable has the same name as the property, but with an "_" prefix. There is a way to change the name of the instance variable, but let's ignore that for now.
The property foo:
#property (nonatomic, strong) NSString *foo;
Would have a getter method:
- (NSString *) foo;
and a setter method
- (void) setFoo: (NSString *) foo;
That enables you to use code like this:
NSString *aString = self.foo;
or
NSString *aString = [self foo];
(2 different, equally valid ways of invoking the getter)
And invoking the setter
self.foo = #"a string";
or
[self setFoo: #"a string"];
(2 different, equally valid ways of invoking the setter)
Properties are really useful when you want to create a public interface to get and set values in your class from outside. If you declare a property as "atomic" the compiler adds additional code to the getter and the setter so reads and writes to the property are "thread safe", and can be accessed from background threads.
Before ARC, properties also were a very clean way to manage retains and releases. You declared a property as "retain" and the setter was written to retain the object that was passed in. That's less of an issue in ARC, because the system takes care of retains and releases for you.
It is also possible to write a custom getter or setter method that invokes your own code instead of the compiler-written code. You can use that to do things like log information, send notifications about changes, update labels, etc, etc. You simply add a method body to your .m file that has the same method signature as the getter or setter and the compiler uses that method instead of the automatically generated one.
As I said before, the code:
self.foo = #"a string";
is the same as
[self setFoo: #"a string"];
and invokes the setter method. The setter method sets the internal instance variable _foo.
However, the code
_foo = #"a string";
changes the instance variable directly, without invoking the setter. If you do define a property, you should use it instead of the instance variable.
Objective-c use to be simple...and tedious. You would declare instance variables for a class (the orange) and then you would define (usually) 2 methods for each, one so that an external class could set each instance variable to a new value, and one that returned the ivars value so an external object could read it. Aka, you had to write a getter and setter for each ivar. This was two lines of code in the interface and sometimes around 10 lines of code for the implementation file.
Then came properties, declared with #property. There was much rejoicing and drinking in the streets. These single #property lines told the compiler to write those methods for you, including the correct memory management code and even mutex locking code (depending on what you specified when declaring the #property)
Theres a whole lot of history, but nowadays, with automatic reference counting, it really only makes sense to use #properties in your interface, when you want to make an ivar public, and declare your private ivars in your implementation file.
Lastly, not that #property not only tells the compiler to implement your getter and setter, but it also automatically provides an instance variable with the same name, but prefixed with an underscore (this is only if you have implicit synthesizing of properies enabled...more history)
So, thats the difference. #property tells the compiler to write code for you (essentially). What code it actually writes is modified by all the different ways you can declare a #property.

"Proper" way to define a class - Properties vs Methods

This is an observation and a question:
I am loading some json data into a class (json already converted into an NSDictionary). The values will be read-only from the outside:
#interface Checklist
-(id)initWithJSON:(NSDictionary *)json;
-(NSInteger)checklist_id;
-(NSString *)checklist_name;
etc....
#end
With the corresponding method bodies in the .m file.
As a test, I created a class for another data element:
#interface ChecklistItem
-(id)initWithJSON:(NSDictionary *)json;
#property (readonly) NSInteger item_id;
#property (readonly) NSString *item_name;
#end
Functionally, the two classes have similar methods in the #implementation. In both cases they basically pull the appropriate value from the json and return the result. And as far as the rest of the program was concerned, the two approaches seem to be interchangeable.
So my question is:
Which approach is the best one to use?
I find either way equally readable and so far I can not find any code-reason to prefer one way over the other. I can kind of see the second option as nice since it kind-of documents the json.
You should use properties, they come in handy once you use KVO.
Also you can define public readonly properties and overwrite them in a class extension with a readwrite property that is only usable in the same class. If you try to achieve something similar you will have to deal with private helper methods — the code gets ugly.
-(NSInteger)checklist_id;
-(NSString *)checklist_name;
This isn't standard Objective-C naming. If you want to do things properly, follow the platform conventions. Apple document this in their coding guidelines documentation.
Which approach is the best one to use?
They are equivalent as far as Objective-C is concerned. The property syntax expresses your intent at a higher level than manually creating the methods, so I would prefer that approach. It's also less code.
This is less important now that ARC will clean up memory which would have been managed
inside the setter but this is still very much best practice. The performance overhead of
calling a setter method is also negligible compared to the safety gained from always
going through the setter.
this is a subjective question and you'll get nothing but opinions back, but here is mine:
the read only properties will just write the getters for you. if you don't write a private read write propertly in your .m file or wherever and just set the ivar's directly you don't even get the will/did change value for key calls and will have to call those yourself also.
#interface ChecklistItem ()
#property (readwrite) NSInteger item_id;
#property (readwrite) NSString *item_name;
#end
To access them KVO complient inside the object you'll have to do:
self.item_id = 13;
And not:
_item_id = 13;
Of course you could just have getter methods:
-(NSInteger)checklist_id;
-(NSString *)checklist_name;
And just wrap all changes in in your KVO methods:
[self willChangeValueForKey:#"checklist_id"];
_item_id = 13;
[self didChangeValueForKey:#"checklist_id"];
it's just a coding style choice, and sometimes leveraging what the compiler will write for you. but either option works the same.
If the values are read only, I'd think you'd want them as methods rather than as read-only properties to avoid any confusion that the values might be able to be set. Unless of course you want the subscribers to be able to use the dot notation for accessing the properties, but if you're just returning the values in the NSDictionary, the method form would be better as you're not keeping around another copy of the data.

iOS: Setting properties

When I'm setting a property with an object that is currently in a retained NSArray, will it only store the pointer (light-weight), or will it copy the contents to the property?
From what I know, it seems like it would only assign the pointer, but I'm not sure.
Also, under what circumstances would using *pointer = *otherPointer or the set methods (setDelegate, for instance) copy the value, instead of just passing the pointer, if any.
Shouldn't it always just pass the pointer address?
It always passes the pointer, as you said. Unless you are specifically adding a de-referencing sign, this will always be the case.
However, when you add a property to a class, and set the setter to copy:
#property (nonatomic, copy) id obj;
When using the dot syntax or the setter, This will be translated to:
_obj = [otherObj copy];
Here, it will depend whether the object in question supports copying itself, or will it fall back to it's super class NSObject or another intermediate class's copy.
Moreover, Collection classes NSDictionary and NSArray do a shallow copy, as in they copy the references to their objects only, so you have two collections pointing to the same set of objects.

iOS property declaration clarification

This is a two part question in hopes that I can understand more about the topic.
1) It seems to me that you have two popular options for declaring a property for a class in objective c. One is to add the property to the header's class body eg.
#interface MyClass : NSObject {
NSArray *myArray;
}
Or you can add it after the #interface body and before the #end statement like so.
#interface MyClass : NSObject {
//
}
#property (nonatomic, retain) NSArray *myArray;
What is the difference between these two "styles" and when do you choose one over the other?
2) after the #property you find options such as (nonatomic, retain). What are those for and why/when do you use different options?
Here are the only property modifiers that Xcode recognizes:
nonatomic (does not enforce thread safety on the property, mainly for use when only one thread shall be used throughout a program)
atomic (enforces thread safety on the property, mainly for use when multiple threads shall be used throughout a program) (default)
retain / strong (automatically retains / releases values on set, makes sure values do not deallocate unexpectedly) (default if ARC and object type)
readonly (cannot set property)
readwrite (can both set and get property) (default)
assign / unsafe_unretained (no memory management shall be done with this property, it is handled manually by the person assigning the value) (default if not ARC or object type)
copy (copies the object before setting it, in cases where the value set must not change due to external factors (strings, arrays, etc).
weak (automatically zeroes the reference should the object be deallocated, and does not retain the value passed in)
getter=method (sets the selector used for getting the value of this property)
setter= method (set the selector used for setting the value of this property)
1) #property is a special way to define getter- and setter-methods, or as we call them accessors in Objective-C. Your first snippet just declares an array for which you have to declare and write accessors yourself. For example setMyArray: and myArray.
Using #property will declare your accessors for you and is equivalent to declaring setMyArray: and myArray yourself. It is the preferred way to declare accessors since Objective-C 2.0. Note that you still have to declare the property (in your case myArray) yourself.
2) You first need to know about #synthesize. Remember that #property DECLARES the accessors for your property, #synthesize will IMPLEMENT them. When you use an #property in your #interface you mostly likely write an #synthesize in #implementation. Using #synthesize is equivalent to implementing setMyArray: and myArray.
The attributes (nonatomic, retain) tell the compiler, among others, how the memory management should work and therefore how the methods will be implemented. Note that you never actually see these accessors, but be assured that they are there and ready for you to be used.
To read more on that topic I recommend reading Section 9 on Properties from the following Tutorial or buy a Book that covers an Introduction to Objective-C.
Also you should familiarize yourself with at least the following attributes:
Access
Choose readwrite (default) or readonly. If readonly is set, ONLY the getter methods will be available.
Setter Memory Management
assign (default), simply assigns the new value. You mostly likely only use this with primitive data types.
retain, releases the old value and retains the new. If you use the garbage collector, retain is equivalent to assign. Why? The manual release of the old value will be done by the garbage collector.
copy will copy the new value and release the old value. This is often used with strings.
Threading
atomic (default) will ensure that the setter method is atomic. This means only one thread can access the setter at once.
nonatomic, use this when you don't work with threads.
This post gives you a good introduction to memory management and assign, retain and copy.
Properties are basically the accessor methods. They define the scope of the variable.
First case as given above,the variable is not accessible in other classes whereas by declaring a property as in the second case,variable is accessible in other classes also.
Also, they are useful for memory management.
First one will be private declaration and will not be accessible by other classes if you do not define the second one. Second is used together with #synthesize in .m module , and setter/getter's are created for you by the compiler. You can still define your own getter or setter with this. In this case all iVars defined in #property can be accessed by other classes.Retain/release operations are done automatically.
You should read Apple documentation for more details.
please check:
What's the difference between the atomic and nonatomic attributes?
Properties are basically the accessor methods. They define the scope of the variable. by default access specifior of variable is protected and properties set its Specifier from protected to Public

Resources