GRMustache core data category not visible? - objective-c

I've a bunch of core data models 'NSManagedObject subclasses' with a couple of categories for each.
I want the template to use attributes from model's category, which is from what I understand is ok since:
[model valueForKey:#"attributeName"];
is actually returning the desired value!
BUT when I evaluate it in a mustache template it returns an empty string!!
so this code snippet is returning an empty string:
NSString *template = #"{{# experiences }}{{experienceElement}}{{/ experiences }}";
return [GRMustacheTemplate renderObject:self fromString:template error:nil];
where self is another model's category that has experiences as an attribute (NSSet) and experienceElement is a function that returns a string in Experience Model's category.
but it works when I replace experienceElement with a real attribute in the Experience model it self!
what is wrong on this implementation?
note: this is a cocoa mac app, using libGRMustache7-MacOS.a

Starting from v 7.0.0 for the sake of security
A new safe key access constraint was introduced to limit keys to only class properties
A solution is to declare a read only property at the category with the name of the method
at category_file.h
#property (nonatomic, readonly) NSString * experienceElement
at category_file.m
-(NSString*) experienceElement
{
NSString *newValue = #"";//derive new value
return newValue;
}

Related

How to appropiately expose parameters in native library for REST API?

I need to write a native Objective-C library to expose REST API resources but I'm having a hard time deciding what is the most appropriate way of exposing the resource's parameters when such parameters are many.
The goal of this library is that it must be easy to use.
So, say that I have a resource: GET /users, it returns a list of Users and I can set parameters in the request to limit the number of results, to filter by name, role, and other criteria. There are many optional parameters that can be set in the request and I have to expose them all in this library.
So far I have three ideas on how to do this:
(the pros/cons are the ones I can see now, doesn't mean there aren't more)
Option A: Create ResourceRequest class for each resource
Define for example a class UsersRequest for accessing the Users resource:
#interface UsersRequest
// Default value: 500 users
#property (nonatomic) int limit;
// The starting point in the ordered list of results
#property (nonatomic) int offset;
// if set, the response will contain only users whose
// id's are in the array. This will override any other parameter.
#property (nonatomic, retain) NSArray* userIDs;
// if set to YES, will filter out users that have been read
#property (nonatomic) BOOL unread;
// defines the users types to filter from the results
#property (nonatomic, retain) NSArray* types;
// if set, it will filter out users not containing the text.
#property (nonatomic, copy) NSString* text;
#end
Then I would be able to access the resource with something like:
UsersRequest* request= [[UsersRequest alloc] init];
request.limit= 100;
request.text= #"test";
request.userIDs= #[#1,#2,#3];
[requestManager sendAsynchronous:request success:^(id response) {
NSLog(#"Success! %#", response);
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
Pros
I like that I only have to create a single method to send the request.
I like that if two or more resources share the same parameter, I can create a hierarchy of ResourceRequest classes and add the specific parameters to specific classes, e.g., say that resource A and B need the limit parameter, then I can define limit as a property of the base class ResourceRequest of ARequest and BRequest
I can use auto-complete to seach for the options I need.
Cons
I have to create one class per resource.
Option B: Pass the parameters as a NSDictionary using constant strings as keys
This implies defining constant strings somewhere:
NSString* const Limit= #"limit";
NSString* const Offset= #"offset";
NSString* const UserIDs= #"UserIDs";
And then calling something like:
NSDictionary* parameters= #{Limit: #50,
Offset: #10,
UserIDs:#[#1, #2, #3]};
[requestManager getUsersWithParams:parameters
success:^(NSArray* usersFound){
NSLog(#"Success! %#", usersFound);
}
failure:^(NSError* error){
NSLog(#"Error: %#", error);
}];
Cons
I have to create one method per resource.
The developer must know the names of the keys for each parameter. He cannot use autocomplete to quickly search for the one he needs.
Option C: Create an RequestParams class and pass that
Define the RequestParams class like:
#interface RequestParams : NSObject
#property (nonatomic) int limit;
#property (nonatomic) int offset;
#property (nonatomic, retain) NSArray* messagesIDs;
#end
And the use as follows:
RequestParams* parameters= [[RequestParams alloc]init];
parameters.limit= 100;
parameters.offset= 20;
parameters.userIDs= #[#1, #2, #3];
[requestManager getUsersWithParams:parameters
success:^(NSArray* usersFound){
NSLog(#"Success! %#", usersFound);
}
failure:^(NSError* error){
NSLog(#"Error: %#", error);
}];
Cons
One method per resource.
Pros
I can use auto-complete to search for the options I need.
I can also create a hieraychy of options classes to refine the options for different resources.
What would be a good way of exposing the resource's parameters? I want to avoid writing methods with 10+ parameters.
Option B doesn't make sense since it has a lack of easiness to use and if you're planning to have a well defined api in order to scale its functionality you will end with tens of constants in your header file.
So is most likely to have option A, you can even have a RequestDelegate
and have some methods maybe for observing the request progress something like
-(void)requestWillPrepareForSend(Request *)request;
or something like
-(void)request:(Request *)request didLoadResponse:(Response *)response;
for handling successful request.
I am not pretty sure what frameworks or libraries are you using to help you handling this scenarios but there should be something out there like AFNetworking that may be is already handled.
Where I'm actually working we have the option C approach and it's a really pain in the ass when you want to unit test a class with tens of methods, so that even though it could be a disadvantage to have a class per resource if you are thinking tdd I recommend to have small chunks of code for unit testing.
If the goal is release an easy to use API, automatically the option B is discarded, due to it doesn't permit autocomplete.
Then I think you must use de option A, with it you can easy organize all parameters per resource and in my experience is much better for code maintenance. The wsdl2java plugin (create class for SOAP comunication) works something like that, a class per resource.
Well, let's see... due to autocomplete issue option B it's no a good idea, will force developers to consult some API documentation every time they write a new request just for know how to write the parameters... option A and option C are both pretty similar but option C makes you write one request per resource in your RequestManager class mixing all the requests, so that option A seems better option to me, one class per resource that handles it's own request (parsing the response and so on), more mainteinable.

How to check private members in objective C unit tests?

Considering this class :
#interface SampleClass : NSObject {
NSMutableArray *_childs;
}
- (void)addChild:(ChildClass *)child;
- (void)removeChild:(ChildClass *)child;
#end
How can i test when i add a child if the _childs array contains one object without adding a property to access it (because i don't want allow client code to access the _childs array) ?
Create a #property for it in the class extension and use the property for all accesses, that way you are testing and using the same code.
I'm not sure I correctly understand your question, I parse it as: While implementing addChild:, how do I prevent to insert objects a second time into _childs ?
There are two ways: if the order of your elements doesn't matter then you should simply use a NSMutableSet instead of an NSMutableArray. In this case the set takes care of everything:
- (void)addChild:(ChildClass *)child
{
[_childs addObject:child];
}
If order is important, stick with the NSMutableArray and do it like this:
- (void)addChild:(ChildClass *)child
{
if ([_childs containsObject:child]) return;
[_childs addObject:child];
}
Just make a -(int)childCount method that returns the count of the array.

Writing my own #dynamic properties in Cocoa

Suppose (for the sake of argument) that I have a view class which contains an NSDictionary. I want a whole bunch of properties, all of which access the members of that dictionary.
For example, I want #property NSString* title and #property NSString* author.
For each one of these properties, the implementation is the same: for the getter, call [dictionary objectForKey:propertyName];, and for the setter do the same with setObject:forKey:.
It would take loads of time and use loads of copy-and-paste code to write all those methods. Is there a way to generate them all automatically, like Core Data does with #dynamic properties for NSManagedObject subclasses? To be clear, I only want this means of access for properties I define in the header, not just any arbitrary key.
I've come across valueForUndefinedKey: as part of key value coding, which could handle the getters, but I'm not entirely sure whether this is the best way to go.
I need these to be explicit properties so I can bind to them in Interface Builder: I eventually plan to write an IB palette for this view.
(BTW, I know my example of using an NSDictionary to store these is a bit contrived. I'm actually writing a subclass of WebView and the properties will refer to the IDs of HTML elements, but that's not important for the logic of my question!)
I managed to solve this myself after pouring over the objective-c runtime documentation.
I implemented this class method:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
NSString *method = NSStringFromSelector(aSEL);
if ([method hasPrefix:#"set"])
{
class_addMethod([self class], aSEL, (IMP) accessorSetter, "v#:#");
return YES;
}
else
{
class_addMethod([self class], aSEL, (IMP) accessorGetter, "##:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
Followed by a pair of C functions:
NSString* accessorGetter(id self, SEL _cmd)
{
NSString *method = NSStringFromSelector(_cmd);
// Return the value of whatever key based on the method name
}
void accessorSetter(id self, SEL _cmd, NSString* newValue)
{
NSString *method = NSStringFromSelector(_cmd);
// remove set
NSString *anID = [[[method stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:#""] lowercaseString] stringByReplacingOccurrencesOfString:#":" withString:#""];
// Set value of the key anID to newValue
}
Since this code tries to implement any method that is called on the class and not already implemented, it'll cause problems if someone tries calling something you're note expecting. I plan to add some sanity checking, to make sure the names match up with what I'm expecting.
You can use a mix of your suggested options:
use the #dynamic keyword
overwrite valueForKey: and setValue:forKey: to access the dictionary
use the objective-c reflection API's method class_getProperty and check it for nil. If it's not nil your class has such a property. It doesn't if it is.
then call the super method in the cases where no such property exists.
I hope this helps. Might seem a bit hacky (using reflection) but actually this is a very flexible and also absolutely "legal" solution to the problem...
PS: the coredata way is possible but would be total overkill in your case...
Befriend a Macro? This may not be 100% correct.
#define propertyForKey(key, type) \
- (void) set##key: (type) key; \
- (type) key;
#define synthesizeForKey(key, type) \
- (void) set##key: (type) key \
{ \
[dictionary setObject];// or whatever \
} \
- (type) key { return [dictionary objectForKey: key]; }
sounds like you should should be using a class instead of a dictionary. you're getting close to implementing by hand what the language is trying to give you.
There is a nice blog with example code with more robust checks on dynamic properties at https://tobias-kraentzer.de/2013/05/15/dynamic-properties-in-objective-c/ also a very nice SO answer at Objective-C dynamic properties at runtime?.
Couple of points on the answer. Probably want to declare an #property in the interface to allow typeahead also to declare the properties as dynamic in the implementation.

Exposing model object using bindings in custom NSCell of NSTableView

I am struggling trying to perform what I would think would be a relatively common task. I have an NSTableView that is bound to it's array via an NSArrayController. The array controller has it's content set to an NSMutableArray that contains one or more NSObject instances of a model class. What I don't know how to do is expose the model inside the NSCell subclass in a way that is bindings friendly.
For the purpose of illustration, we'll say that the object model is a person consisting of a first name, last name, age and gender. Thus the model would appear something like this:
#interface PersonModel : NSObject {
NSString * firstName;
NSString * lastName;
NSString * gender;
int * age;
}
Obviously the appropriate setters, getters init etc for the class.
In my controller class I define an NSTableView, NSMutableArray and an NSArrayController:
#interface ControllerClass : NSObject {
IBOutlet NSTableView * myTableView;
NSMutableArray * myPersonArray;
IBOutlet NSArrayController * myPersonArrayController;
}
Using Interface Builder I can easily bind the model to the appropriate columns:
myPersonArray --> myPersonArrayController --> table column binding
This works fine. So I remove the extra columns, leaving one column hidden that is bound to the NSArrayController (this creates and keeps the association between each row and the NSArrayController) so that I am down to one visible column in my NSTableView and one hidden column. I create an NSCell subclass and put the appropriate drawing method to create the cell. In my awakeFromNib I establish the custom NSCell subclass:
MyCustomCell * aCustomCell = [[[MyCustomCell alloc] init] autorelease];
[[myTableView tableColumnWithIdentifier:#"customCellColumn"]
setDataCell:aCustomCell];
This, too, works fine from a drawing perspective. I get my custom cell showing up in the column and it repeats for every managed object in my array controller. If I add an object or remove an object from the array controller the table updates accordingly.
However... I was under the impression that my PersonModel object would be available from within my NSCell subclass. But I don't know how to get to it. I don't want to set each NSCell using setters and getters because then I'm breaking the whole model concept by storing data in the NSCell instead of referencing it from the array controller.
And yes I do need to have a custom NSCell, so having multiple columns is not an option. Where to from here?
In addition to the Google and StackOverflow search, I've done the obligatory walk through on Apple's docs and don't seem to have found the answer. I have found a lot of references that beat around the bush but nothing involving an NSArrayController. The controller makes life very easy when binding to other elements of the model entity (such as a master/detail scenario). I have also found a lot of references (although no answers) when using Core Data, but Im not using Core Data.
As per the norm, I'm very grateful for any assistance that can be offered!
Finally figured this one out. Man that took some doing. So here is what I needed to do...
First of all I needed to create an array of my model's key values in my model object and return those key values in an NSDictionary from within the model.
Thus my model got two new methods as follows (based on my simplified example above):
+(NSArray *)personKeys
{
static NSArray * personKeys = nil;
if (personKeys == nil)
personKeys = [[NSArray alloc] initWithObjects:#"firstName", #"lastName", #"gender", #"age", nil];
return personKeys;
}
-(NSDictionary *)personDictionary
{
return [self dictionaryWithValuesForKeys:[[self class] personKeys]];
}
Once implemented, I assign my bound value in my table to
arrayController --> arrangeObjects --> personDictionary.
The last step is to reference the object in the NSCell drawWithFrame and use as needed as follows:
NSDictionary * thisCellObject = [self objectValue];
NSString * objectFirstName = [thisCellObject valueForkey:#"firstName"];
NSString * objectLastName = [thisCellObject valueForKey:#"lastName"];
And as I hoped, any update to the model object reflects in the custom NSCell.
There is another approach that does not require the dictionary. However, it does require the implementation of the - (id)copyWithZone:(NSZone *)zone method within your data class. For example:
- (id)copyWithZone:(NSZone *)zone {
Activity *copy = [[self class] allocWithZone: zone];
copy.activityDate = self.activityDate;
copy.sport = self.sport;
copy.sportIcon = self.sportIcon;
copy.laps = self.laps;
return copy; }
Now in IB, you point the Table Column's value at Array Controller --> arrangedObjects
The drawWithFrame method will now return your actual object from the objectValue.
Activity *rowActivity = [self objectValue];
Changing the class requires updating the copyWithZone method and then accessing the data directly in your drawWithFrame method.
I'm very grateful for this post, Hooligancat, because my project was stalled on this problem, and as hard as I looked at Tim Isted's identical solution at http://www.timisted.net/blog/archive/custom-cells-and-core-data/
I couldn't figure it out.
It was only when I read your excellent simplification of the problem and your version of the solution that the penny dropped - I'm very grateful!

How to detect a property return type in Objective-C

I have an object in objective-c at runtime, from which I only know the KVC key and I need to detect the return value type (e.g. I need to know if its an NSArray or NSMutableArray) of this property, how can I do that?
You're talking about runtime property introspection, which happens to be something that Objective-C is very good at.
In the case you describe, I'm assuming you have a class like this:
#interface MyClass
{
NSArray * stuff;
}
#property (retain) NSArray * stuff;
#end
Which gets encoded in XML something like this:
<class>
<name>MyClass</name>
<key>stuff</key>
</class>
From this information, you want to recreate the class and also give it an appropriate value for stuff.
Here's how it might look:
#import <objc/runtime.h>
// ...
Class objectClass; // read from XML (equal to MyClass)
NSString * accessorKey; // read from XML (equals #"stuff")
objc_property_t theProperty =
class_getProperty(objectClass, accessorKey.UTF8String);
const char * propertyAttrs = property_getAttributes(theProperty);
// at this point, propertyAttrs is equal to: T#"NSArray",&,Vstuff
// thanks to Jason Coco for providing the correct string
// ... code to assign the property based on this information
Apple's documentation (linked above) has all of the dirty details about what you can expect to see in propertyAttrs.
Cheap answer: use the NSObject+Properties source here.
It implements the same methodology described above.
The preferred way is to use the methods defined in the NSObject Protocol.
Specifically, to determine if something is either an instance of a class or of a subclass of that class, you use -isKindOfClass:. To determine if something is an instance of a particular class, and only that class (ie: not a subclass), use -isMemberOfClass:
So, for your case, you'd want to do something like this:
// Using -isKindOfClass since NSMutableArray subclasses should probably
// be handled by the NSMutableArray code, not the NSArray code
if ([anObject isKindOfClass:NSMutableArray.class]) {
// Stuff for NSMutableArray here
} else if ([anObject isKindOfClass:NSArray.class]) {
// Stuff for NSArray here
// If you know for certain that anObject can only be
// an NSArray or NSMutableArray, you could of course
// just make this an else statement.
}
This is really a comment addressing an issue raised by Greg Maletic in response to answer provided by e.James 21APR09.
Agreed that Objective-C could use a better implementation for getting these attributes.
Below is a method I quickly threw together to retrieve attributes of a single object property:
- (NSArray*) attributesOfProp:(NSString*)propName ofObj:(id)obj{
objc_property_t prop = class_getProperty(obj.class, propName.UTF8String);
if (!prop) {
// doesn't exist for object
return nil;
}
const char * propAttr = property_getAttributes(prop);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *attrArray = [propString componentsSeparatedByString:#","];
return attrArray;
}
Partial list of attribute keys:
R Read-only
C Copy of last value assigned
& Reference to last value assigned
N Nonatomic property
W Weak reference
Full list at Apple
You can use isKindOfClass message
if([something isKindOfClass:NSArray.class])
[somethingElse action];
If you know that the property is defined :
id vfk = [object valueForKey:propertyName];
Class vfkClass = vfk.class;
And compare with isKindOfClass, isSubClass, etc.