Coercing a KVC type - cocoa

I would like to parse XML to populate KVC compliant objects but, my parser is very dumb, it simply assembles NSStrings from the XML attributes/tags and tries to set them via KVC.
This works for actual strings and numbers (I believe) but I need to also set dates. The problem is obviously that the parser doesn't know the string represents a date and it tries to sit it using the vanilla KVC calls - afterwhich the KVC framework complains about the type mismatch (setting a string on a date field).
Is there a programmatic way to 'intercept' invocations into the KVC framework such that I can alter the data being set (run a date string through an NSDateFormatter)?
I could put some intelligence into the parser but before doing so, are there any other well-known solutions for this type of problem?

This might not be the perfect solution, but... I'd like to share my ideas ;)
So, first of all, take a look here: Key-Value Coding - Validation. That document describes a neat way to validate your variable the moment it's set via KVC. You could use this to your advantage by:
First implement KV Validation method for your class variable
Set your value
In your validation method check if it's a date/string/whatever you wish - and change it to proper type.
This should provide a clean implementation for ensuring proper type.
Cheers,
Pawel

With KVC, everything goes through a default implementation of setValue:forKey: whichs calls the appropriate mutator method (as described here).
You can just override setValue:forKey: to check for the key or keys that need transforming, and make appropriate changes.
- (void)setValue:(id)value forKey:(NSString *)key
{
if([key isEqualToString:#"someDate"]) {
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
someDate = [dateFormatter dateFromString:value];
value = somedate;
}
[super setValue:value forKey:key];
}
That's from memory, so no guarantees whether it'll actually compile and run. ;-)

Related

Detect attempt to insert nil on a dictionary and log a backtrace

Is there a way I can detect an attempt to insert a nil value on a dictionary and log a backtrace on my application ?. I know how to do it with Xcode, but the error occurs only with some users. Hence I need to send them a new build that hopefully would log a backtrace of the attempted nil insertion.
This is probably because an image or a font is not being loaded correctly, if there is another way to find out I would also like to know.
You can't do this with regular NSMutableDictionary objects, as adding a nil value is legal.A workaround would be to use a custom dictionary implementation that wraps a NSDictionary instance and forwards all methods to the wrapped objects; and in the case of setObject:forKey: (or setValue:forKey:) makes a check and logs the backtrace if the value is nil. The downside is that you'll have a lot of boiler plate code to write. You can reduce the boiler plate code size if you implement only the methods needed by your code.
Another approach would be to use method swizzling and replace the setObject:forKey: and setValue:forKey: with your method that firstly checks the value and if OK forwards the call to the original method. However NSDictionary being a class cluster you might experience problems with this approach.
Update. Just thought of a 3rd solution: add a category over NSMutableDictionary with getters/setters for the keys you're interested in, and update your code to call those setters instead of the setObject:forKey: method.
As I understand your problem you have failed to check the result when loading an image, font or something similar and this is causing an error when the bad result is later inserted into a dictionary. What you are after is a quick way, as you have a large codebase, to track down that insertion so you can backtrack and find the source of the problem and add appropriate checking code to the load/whatever.
What you can do is:
Replace NSMutableDictionary with a simple class, say DebuggingDictionary, which appears to be (explained below) a derived class and just checks for nil on insertion and produces the diagnostics you are after; and
Do a find/replace over your code base for [NSMutableDictionary alloc] and replace with [DebuggingDictionary alloc]. You can easily change this back once the problem has been fixed.
So how to write DebuggingDictionary?
Well as NSMutableDictionary is a class cluster you cannot just derive from it and override setObject:forKey:, you have provide your own storage for the keys & objects and override six key methods and all (or at least all you use) of the init methods.
Sounds bad but it isn't. First read this answer to a different but related question. In that answer a version of NSMutableArray is created which checks the type of elements added, you need to check whether the items are nil. The implementation provides the storage by wrapping a real NSMutableArray. You can do the equivalent with NSMutableDictionary, the documentation (NSMutableDictionary and NSDictionary) lists the six primitive methods you need to override.
That answer also adds its own initWithClass: initialisers and blocks the standard ones, you just need to implement the standard dictionary ones - by calling them on the wrapped dictionary.
[Minimal checking in the following code sketches, all typed directly into answer so beware of typos]
So for example initWithCapacity: becomes something like:
- (instancetype) initWithCapacity:(NSUInteger)numItems
{
realDictionary = [NSMutableDictionary dictionaryWithCapacity:numItems];
return self;
}
and the core insertion method becomes:
- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey
{
if (anObject == nil)
{
// produce your diagnostics
}
else
realDictionary[aKey] = anObject;
}
Once you've tracked your problem to its source and fixed it there just remove your DebuggingDictionary and find/replace all occurrences in your code with NSMutableDicitionary.
HTH
You could create subclass of NSAplication and override method reportException
Use
+[NSThread callStackSymbols];
or
-[NSException callStackSymbols];
to get a backtrace. You can print a backtrace using NSLog.
You may find also Apple's example useful for you:
ExceptionReporting:
Demonstrates how to show a customized exception reporting user interface.
This lets the user know when the exception happens in order to possibly prevent
subsequent random crashes that are difficult to debug.
Instead of setting key/value directly to the dictionary, how about using a method that accepts parameters that should be inserted into the dictionary and tests each for nil before adding it to the dict?
-(void)addKeyAndValueToDict:(NSString*)aKey andValue:(NSString *)aValue {
if ( aValue == nil ) {
NSLog(#"value was nil for key: %#", aKey);
return;
}
[self.someDict setValue:aValue forKey:aKey];
}

Xcode:(user defined runtime attribute)Range with minus value. Alternative?

I made a custom UITextField with an additional user defined runtime attribute validRange, which I can set in the storyboard view.
I use this property to check in the EndEditing method to validate the new set text.
I works all fine, till I had to set a valid range from {-100,100}
As NSRange uses NSUInteger, there are no minus values possible.
What is the best way to still make this happen?
Would it be acceptable if I use CGSize instead of NSRange?
Updated Content
Xcode only gives me the following choice of data types for the user defined runtime attributes:
This means I cannot define a new struct to create a CustomRange with NSInteger.
As Point,Size are both {NSInteger,NSInteger} data types, I thought about using them. But this would be certainly a misuse, so I am wondering if someone knows a better solution, as misusing Point or Size to get this to work.
As another workaround I could user String, which I manually would split up in a method of the custom UITextField, but then there is no type safety.
Then I would suggest you to define two NSNumber properties with suitable names to represent NSRange value instead of abusing CGSize as using CGSize confuses other readers/programmers as we there is a saying, we code for others not for ourselves.
And there is a NSNumber class method as follows
+ (NSNumber *)numberWithInteger:(NSInteger)value
which allow you to wrap signed integer value as you intend.

implementing custom accessor methods

I am reading "Core Data Programming Guide". It contains this text:
You must, however, change attribute values in a KVC-compliant fashion.
For example, the following typically represents a programming error:
NSMutableString *mutableString = [NSMutableString stringWithString:#"Stig"];
[newEmployee setFirstName:mutableString];
[mutableString setString:#"Laura"];
For mutable values, you should either transfer ownership of the value
to Core Data, or implement custom accessor methods to always perform a
copy. The previous example may not represent an error if the class
representing the Employee entity declared the firstName property
(copy) (or implemented a custom setFirstName: method that copied the
new value). In this case, after the invocation of setString: (in the
third code line) the value of firstName would then still be “Stig” and
not “Laura”.
Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?
Question regarding copy and programming practice:
From what I have read here:
NSString property: copy or retain?
I understand
that using copy will ensure that firstName is "Stig", not Laura
it is wise to do so because "in almost all cases you want to prevent mutating an object's attributes behind its back"
I would really like to know what is the above quoted text trying to tell us in the context of Core Data. We have to use "copy" anyway whether using Core Data or not. Also, I would be glad if someone could throw more light on point "2" (it is wise to...) above as in what will be the consequences of mutating an object's attributes behind its back?
your "Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?"
mis-matched the point that Apple document wants to explain, I believe.
As Apple document points out, if custom-accessor-method is implemented normally, the default implementation does NOT copy attribute values. If the attribute value may be mutable and implements the NSCopying protocol (as is the case with NSString, for example), you can copy the value in a custom accessor to help preserve encapsulation (for example, in the case where an instance of NSMutableString is passed as a value).
Here is a copying setter snippet
#interface Department : NSManagedObject
{
}
#property(nonatomic, copy) NSString *name;
#end
#implementation Department
#dynamic name;
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:#"name"];
// NSString implements NSCopying, so copy the attribute value
NSString *newNameCopy = [newName copy];
[self setPrimitiveName:newNameCopy];
[self didChangeValueForKey:#"name"];
} #end
The issue is when to use (and how) immutable values.
Since core data use KVO heavily when detecting changes done to objects, if you use a mutable property that is changed directly through it object and not through the property, CoreData will not detect the change to the object and your changes might not persist to the store.
If you use mutable NSManagedObject attributes, override the setter/getter method and use only them to mutate the underlying object (this mean that you are responsible to let CoreData know that a change did happen to the object, and it must be persisted to the store.
Also, if you use transformable properties for complex objects, you must trigger the change notifications yourself in order for CoreData to realise that a change has occurred, and the object should be re-transformed and saved when the context saves.
I would highly recommend that when it comes to simple objects like strings, you use immutable property values which will force you to go through the object properties and trigger the default KVO notification (copy attributes will also force the KVO notifications).

Key-Value Coding and methods calling

It's a question about good programming techniques with Cocoa.
When you want to call a method on one property of your class, should you use KVC to get the receiver or just put the name of your property?
Example, KVC:
[[self property] myMethod];
Example, simple:
[property myMethod];
Thanks!
Example, KVC:
[[self property] myMethod];
That isn't KVC. The KVC way is:
[[self valueForKey:#"myProperty"] myMethod]
There is no reason to do this when you know the property at compile time; you can just ask for the property value or the ivar value directly. With KVO and (on the Mac) Bindings already implemented, there's not much reason to use KVC directly, as KVO and Bindings use it for you.
Example, simple:
[property myMethod];
That doesn't access the property; it accesses the ivar.
You're only accessing the property when you send an accessor message to the property's holder (self in your examples). It doesn't matter whether you use [self property] or self.property, as they're equivalent; either one is a property message to self, with whatever side effects that implies.
That's the key difference: Hitting the accessor may cause side effects, whereas accessing the ivar directly never will.
Hence, the best practice: Use the property in all your instance methods (as you probably want the accessors' side effects), except in init methods and dealloc, where side effects would be a bad thing. (As a general rule, you should not send messages to a half-initialized or half-deallocked object. The exception is when you explicitly commented the method as being part of your init/dealloc process and therefore wrote it to be safe to use in such circumstances.)
I believe the formal version is technically correct as that will guarantee any side-effects from a funky getter. (To make sure, make a custom getter that includes NSLog("in getter!") and let us know if it works.)
For setting you have to use the [self setProperty:foo]; as property = foo bypasses the setter and can lead to memory leaks.
If it feels more natural to you, the dot notation (e.g., self.property and self.property = foo) is identical to [self property] and [self setProperty:foo].

override description or stringValue in cocoa?

I want to have an descriptive string for an object in Cocoa. I'm thinking about overriding either the description method or the stringValue method. Which is preferable and why? The only guideline I could find was in here stating
You are discouraged from overriding description.
Is this indeed what you would suggest? Any other preferred overrride point?
I personally override description in virtually all subclasses I create. I guess, like Tom Duckering writes in his comment, that your quote only applies to Managed Objects.
- (NSString *)description
{
return [NSString stringWithFormat:#"%# <%p>", NSStringFromClass([self class]), self];
}
description is the way to go, that's what it's called to supply string representation of an object.
- (NSString*)description
{
return [NSString stringWithFormat:#"%#, %#; %#", a, b, c];
}
I believe suggested by Hillegass' book as well.
To answer your question from the other direction, stringValue is something altogether different—it doesn't describe the receiver, it's a property of it. Your custom description may even include the stringValue, or an excerpt of it if it's long.
A key difference is that stringValue is often a mutable property (see, for example, that of NSControl), whereas description is always an immutable property, computed upon demand.
You can also override [NSObject debugDescription] which is called by the debugger. It's what is called when use "print to console" in the debugger. You can also call it directly in a NSLog.
By default in most classes debugDescription just calls description but you can make them return separate strings. It's a good place to load up the output with details.
Categories are a good place to park the method for both your custom classes and existing classes. This is especially useful because you can include the category in a debug build but exclude it in the release. If the category is not present, the code calls the default class method instead.
I have a debugging category for UIView that dumps out every attribute I could think of. If I hit a nasty bug I just include the category and then I can see everything about every view right in the debugger console.

Resources