I'm trying to understand some theory part in Objective C related to KVC. Following is the example I've done.
I'm having class call Cookie and it has a property like below
#property NSString *name;
Next, I have another class call Person and it has following property
#property Cookie *cookie;
Inside Person implementation file
#import "Cookie.h"
- (id)init
{
self = [super init];
if (self) {
_cookie = [[Cookie alloc] init];
}
return self;
}
In my ViewContrtoller I can write following two options to get the same result.
Using KVC :
[me valueForKeyPath:#"cookie.name"]
Using accessor methods :
[[me cookie] name]
To write accessor method , I had to import the Cookie class but doesn't need when using KVC.
Apart from that, what are the benefit of using KVC instead or using accessor methods? Is there any performance issue or security issue or good coding practice or any other benefit?
One situation where i found KVC very handy was when i had to perform some kind of operation on a collection object such as finding the average of a particular value.Specifically I used KVC operators.
For example
[myDict valueForKey:#"gamePoints"] valueForKey:#"doubleValue"] valueForKeyPath:#"#max.self"];
This will help you find the maximum value for the property 'gamePoints' from among an array of dictionaries/ objects.
Here is an excellent article by Mattt Thompson
Hope this contributes to what you are looking for.
There's no particular benefit in this case to using KVC. In general, you should prefer to use the accessors or dot syntax (e.g. me.cookie.name) when you can.
KVC is for when the name of the property you want to access is dynamic. It's not known at compile time. It comes from data (including a NIB, in the case of bindings on OS X) or is computed.
According to the Apple Docs:
Though key-value coding is efficient, it adds a level of indirection that is slightly slower than direct method invocations. You should use key-value coding only when you can benefit from the flexibility that it provides.
But I think this is probably a little over-cautious; I doubt you need worry too much unless your app is very performance sensitive.
Beside the given answers (+1) you get the advantage of identifier completion in Xcode which reduces the probability of typos. Importing the class is a good strategy, if you use it semantically. Look at it as a "bill of things I use", which can be helpful for understanding your code.
Great place to use KVO is unit testing. When you have following class interface:
#interface ServerCommunicationManager : NSObject
{
NSMutableArray *commandQueue;
BOOL chanelFree;
}
- (void)send:(NSDictionary *)dictionary;
#end
And then send implementation:
- (void)send:(NSDictionary *)json
{
if ( YES == chanelFree ) {
// send command immediately
} else {
[commandQueue addObject:json];
}
}
If we want to test send implementation without exposing commandQueue(hence without braking encapsulation) we could get use of KVO:
-(void)testSend
{
ServerCommunicationManager* aTestObj = [ServerCommunicationManager new];
//prepare conditions
[aTestObj setValue:#NO forKey:#"channelFree"];
NSDictionary* dummyReq = #{};
[aTestObj send:dummyReq];
//check commandQueue state
XCTAssertEqualObjects(dummyReq, [[aTestObj valueForKey:#"commandQueue"] firstObject]);
XCTAssertTrue(1 == [[aTestObj valueForKey:#"commandQueue"] count]);
//more tests
}
KVC allows you to do KVO: That is, if you are observing a variable, you will only be notified of its changes if and only if the changes take place using KVC. If you modify a variable directly using its setter you are not going to be notified of its changes
Related
We have a weird memory leak, but since the code is closed source I can't just post the code so I'll do my best to make sure the important bits are available.
Disclaimers:
I can't post the complete backtrace, but if you want to see it I'll do my best to produce an obfuscated version
I can't post complete class definitions, but I am including the parts that have been run in this scenario, obfuscated.
What I hope to learn
I want to know why this happens, not get a solution. Or perhaps when I know what happens, I'll know how to better solve it if there's a better way than making them lazy.
Problem
These default values leak
Pricing:
#objcMembers
class Pricing: Mappable {
var price: Money = Money.zero()
var vat: Percent = Percent.zero()
...
}
Some related information
These two properties leak. From what I can gather, these instances of zero are immediately lost as our ObjC interface Mappable has a category called Mappable+JSONMappings which provides a default implementation of our JSON deserialisation initialised, initWithJSON:, in Objective C for all objects that implement Mappable. This means that all you have to do is claim to implement it, and then you get this initialiser which is then called by our deserialiser, magic!
However, we get two separate leaks every time we deserialise this Pricing object. One for the Money class and its internal NSDecimalNumber and one for Percent. Fixing Money fixes NSDecimalNumber. This is consistent and they leak the exact same way when I look at the memory graph.
Mappable was originally used only by our ObjC models, as our Swift models we had up until this point were structs that implemented Codable to achieve the same result, just using JSONDecoder. This model had to be used in the legacy parts of our system and thus needed to also use Mappable, but we went with Swift in order to use Swift features not available in ObjC, such as enum Enum: String and such, which are used internally by Pricing for whatever reasons.
Money.m:
#interface Money()
#property (nonatomic, strong) NSDecimalNumber *value;
#property (nonatomic, strong) NSString *currencyCode;
#end
#implementation Money
+ (instancetype)zero {
return [Money initWithDecimal:[#(0) decimalValue]];
}
+ (instancetype)initWithDecimal:(NSDecimal)decimal {
return [[self alloc] initWithDecimal:decimal];
}
- (instancetype)initWithDecimal:(NSDecimal)value {
return [self initWithDecimal:value currency:[[CurrencySettings getInstance] getCurrency]];
}
- (instancetype)initWithDecimal:(NSDecimal)value currency:(NSString *)currencyCode {
self = [super init];
if (self) {
_currencyCode = currencyCode;
_value = [NSDecimalNumber decimalNumberWithDecimal:value];
}
return self;
}
#end
I have found a method which is called frequently in our internal JSON deserialisation implementation. It builds our data recursively using this NSObject method:
[self setValue:value forKey:key]
TL;DR;
We have an internal ObjC JSON deserialisation layer that through magic implements default methods for things implementing an interface. This calls on the following method frequently:
[self setValue:value forKey:key]
[NSObject setValue: forKey:]
According to the docs it says the following:
If key identifies a to-one relationship, relate the object specified by value to the receiver, unrelating the previously related object if there was one. Given a collection object and a key that identifies a to-many relationship, relate the objects contained in the collection to the receiver, unrelating previously related objects if there were any.
The search pattern that setValue:forKey: uses is described in Accessor Search Patterns in Key-Value Coding Programming Guide.
In a reference-counted environment, if the instance variable is accessed directly, value is retained.
Debugging and tracing
We have Automatic Reference Counting (ARC) enabled on the target and right now these are the only leaks we have currently in a pretty big project, and the usage of Money.zero() is used elsewhere very frequently as well, indicating it is not actually a problem with the Money class itself.
The memory graph for Money is not very informative and displays only this:
The graph for NSDecimalNumber shows that Money is at fault, though:
Inspecting the graph for Percent will show the same sort of relationship.
Making the properties lazy
A workaround is to make the properties lazy. It does not give us any insights as to why it happened though, so this is why I am posting here.
#objcMembers
class Pricing: Mappable {
lazy var price: Money = Money.zero()
lazy var vat: Percent = Percent.zero()
...
}
What is this syntax when I was attempting to override a getter??
I'm just messing around trying to learn more about how properties work in Objective-C. Here is my property:
#property (nonatomic, strong) UIView *myView;
When I try to override the getter I get this help:
-(void)getMyView:(<object-type> **)buffer range:(NSRange)inRange
{
}
I know I can use this:
-(UIView *)myView
{
}
But I am just curious as to what the previous method does, why it's there, etc. Thanks for any help!
It's called "Getter Indexed Accessors" as explained in the Key-Value Coding Programming Guide
From the documentation:
In order to support read-only access to an ordered to-many relationship, implement the following methods:
-countOf<Key> Required. This is the analogous to the NSArray primitive method count.
-objectIn<Key>AtIndex: or -<key>AtIndexes: One of these methods must be implemented. They correspond to the NSArray methods objectAtIndex: and objectsAtIndexes:
-get<Key>:range: Implementing this method is optional, but offers additional performance gains. This method corresponds to the NSArray method getObjects:range:.
You can implement such methods for performance reasons, as explained in the guide
If benchmarking indicates that performance improvements are required, you can also implement -get<Key>:range:. Your implementation of this accessor should return in the buffer given as the first parameter the objects that fall within the range specified by the second parameter.
As an example
- (void)getEmployees:(Employee * __unsafe_unretained *)buffer range:(NSRange)inRange {
// Return the objects in the specified range in the provided buffer.
// For example, if the employees were stored in an underlying NSArray
[self.employees getObjects:buffer range:inRange];
}
I'm writing an iOS app where there is a common object that all views within the app need to access.
I have been creating, and initialising the object within the viewDidLoad event (of the first view controller), and then passing a reference to this object to all other views that need it. This does not seem like the correct way to do things, feels like I'm somehow breaking the MVC pattern since I'm relying that this particular view is always the first to load in order to setup objects that the whole application needs.
I have now modified my app to do the basic object creation and initialisation in the appDelegate "didFinishLaunching...". This is now working and I can access this common object from all of my other views without having to pass around a reference from one view to the other.
Before I go and continue too far, I was hoping to get peoples input on whether this is the correct way to do things, or whether I should be doing anything else? Sorry if this seems like a trivial question, I'm just learning and want to learn how to do things properly.
Thanks in advance :-)
Without repeating what has already been answered, I'd suggest you make your own Singleton object to hold your 'globals', so you don't clutter your AppDelegate with it.
#interface MyGlobalDataController : NSObject
#property (nonatomic, strong) MyData *myData;
+(MyGlobalDataController *)sharedInstance;
#end
#implementation MyGlobalDataController
static MyGlobalDataController *MyGlobalDataControllerSharedInstance = nil;
- (id)init {
self = [super init];
if (self) {
// do whatever needs doing
}
return self;
}
+(MyGlobalDataController *)sharedInstance {
#synchronized(self) {
if (MyGlobalDataControllerSharedInstance == nil) {
MyGlobalDataControllerSharedInstance = [[MyGlobalDataController alloc] init];
}
}
return MyGlobalDataControllerSharedInstance;
}
#end
The first time you access your sharedInstance, the init will be called, so you don't have to worry about timing there.
Putting your global object initialisation in didFinishLaunching is a better idea than having it in didLoad.
Some people will disagree with me here and say you shouldn't have globals full stop, but personally I think having some sort of global state is acceptable. I love a good object-orientated app but there is a balance to be struck between solid OOP and the flexibility provided by having a few globals.
I think ultimately do whatever is right for you, the major disadvantage of having a global state is that it becomes difficult to maintain and has the potential to introduce a lot of bugs / unexpected behaviour especially in a large app, whereas if you stick to the MVC pattern then each view in your app simply does what it is meant to without unnecessarily affecting other parts of the app.
Nowadays, I tend to stick to MVC / OOP principles for the most part, but have an [AppDelegate]sharedAppDelegate] singleton I can use to access variables at certain points. I have very, very few variables in here but they do come in handy i.e. now my app has a shared 'loading HUD' which is managed by this class, and my sharedAppDelegate also contains a lot of static methods for initiating HTTP, parsing JSON etc which saves a lot of time.
One alternative to having global information in your appDelegate is using NSUserDefaults to store key-value information
Hope that helps anyway, like I said some people will disagree with me but ultimately it boils down to personal preferences, and where the balance for you in terms of rigidity to the MVC model versus flexibility is
So I want to have a "property" on a class but I don't want to just hold that property in memory, I want to actually store it as an NSUserDefault and retrieve it when you get that property.
So as such I have methods like this:
- (void)setUser:(User *)user {
// actually set the user as an NSUserDefault here
}
- (User *)user {
// get the user from the NSUserDefaults and return it
}
As I'm building these methods to do the work for me is there any point in having an #property declaration in the header file?
I'm getting mixed messages. Some people say that you should declare the property to force people to use the getter/setter methods, but I can't see why people wouldn't be forced to use those methods if they're all that are available?
Just looking for a bit of clarification.
Many thanks.
You should use #property because that's the modern way to define properties on Objective-C objects, even if you implement the setter and getter yourself.
Rather than relying on convention you are making your intentions much clearer to the compiler. You will also get better syntax highlighting when using dot-notation in the IDE (although that's arguably an Xcode bug).
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.