OCMock with Core Data dynamic properties problem - cocoa

I'm using OCMock to mock some Core Data objects. Previously, I had the properties implemented with Objective-C 1.0 style explicit accessors:
// -- Old Core Data object header
#interface MyItem : NSManagedObject {}
- (NSString *) PDFName;
- (void) setPDFName:(NSString *)pdfName;
#end
// -- implementation provides generated implementations for both getter and setter
Now I've moved the code to Objective-C 2.0 and want to take advantage of the new #property syntax, and the dynamically-generated method implementations for Core Data objects:
// -- New Core Data object header
#interface MyItem : NSManagedObject {}
#property (nonatomic, retain) NSString *PDFName;
#end
// -- Core Data object implementation
#implementation MyItem
#dynamic PDFName;
#end
However, now when I create a mock item, it doesn't seem to handle the dynamic properties:
// -- creating the mock item
id mockItem = [OCMockObject mockForClass:[MyItem class]];
[[[mockItem stub] andReturn:#"fakepath.pdf"] PDFName]; // <-- throws exception here
The error looks like this:
Test Case '-[MyItem_Test testMyItem]' started.
2009-12-09 11:47:39.044 MyApp[82120:903] NSExceptionHandler has recorded the following exception:
NSInvalidArgumentException -- *** -[NSProxy doesNotRecognizeSelector:PDFName] called!
Stack trace: 0x916a4d24 0x92115509 0x97879138 0x978790aa 0x9090cb09 0x97820db6 0x97820982 0x10d97ff 0x10d9834 0x9782005d 0x9781ffc8 0x20103d66 0x20103e8c 0x20103642 0x20107024 0x20103642 0x20107024 0x20103642 0x20105bfe 0x907fead9 0x977e4edb 0x977e2864 0x977e2691 0x90877ad9 0xbf565 0xbf154 0x107715 0x1076c3 0x1082e4 0x89d9b 0x8a1e5 0x894eb 0x907e81c7 0x978019a9 0x978013da 0x907dd094 0x907ea471 0x9478c7bd 0x9478c1b9 0x94784535 0x5ede 0x326a 0x5
Unknown.m:0: error: -[MyItem_Test testMyItem] : *** -[NSProxy doesNotRecognizeSelector:PDFName] called!
Am doing something wrong? Is there another way to mock a Core Data / object with #dynamic prooperties?

Also responded to your cross-post on the OCMock Forum
Check out http://iamleeg.blogspot.com/2009/09/unit-testing-core-data-driven-apps.html.
Basically he suggests abstracting out your Core Data object's interface to a protocol, and using that protocol instead of the class where you pass instances of your core data object around.
I do this for my core data objects. Then you can use mockForProtocol:
id mockItem = [OCMockObject mockForProtocol:#protocol(MyItemInterface)];
[[[mockItem expect] andReturn:#"fakepath.pdf"] PDFName];
Works great! He also suggests creating a non-core data mock implementation of the interface which just synthesizes the properties:
#implementation MockMyItem
#synthesize PDFName;
#end
...
id <MyItemInterface> myItemStub = [[MockMyItem alloc] init] autorelease];
[myItem setPDFName:#"fakepath.pdf"];
I've used this as well, but I'm not sure it adds anything over the mockForProtocol:/stub: approach, and it's one more thing to maintain.

The above answer didn't satisfy me, because I didn't like to create a protocol for that. So I found out that there is an easier way to do that.
Instead of
[[[mockItem stub] andReturn:#"fakepath.pdf"] PDFName]; // <-- throws exception here
Just write
[[[mockItem stub] andReturn:#"fakepath.pdf"] valueForKey:#"PDFName"];

One of solutions is using a protocol, which is intended to substitute it's original interface, but it could be a bit heavy and leads to significant amount of code you should duplicate.
Personally, I found a way to make it lightweight:
Create a simple category, for instance, inside your unit testing file, just before your unit testing class:
#implementation MyItem(UnitTesing)
- (NSString *)PDFName{return nil;};
#end
Also, you can keep it in separate file, but make sure, that this file is not a part of your production target. That is why I prefer to keep it in the same test file, where I want to use it.
The huge advantage of this method, is that you should not copy methods, that are created by XCode to support relationships. Also you can put to this category only methods you are going to call inside your tests.
There are some caveats, though, for example, you should add another methods inside the category, to support setters, when you are going to check, how correct your code changes the properties of your managed object:
- (void)setPDFName:(NSString *)name{};

Related

How can I bind to NSTableColumn's headerTitle?

I would like to bind NSTableColumn's headerTitle property to an NSMutableArray in my model layer (via an NSArrayController).
Basically I want to have an array where I can change values and have the table column header titles update. Is that reasonable?
However, the headerTitle binding wants an single NSString and I'm not sure how to connect my model object to this binding via my NSArrayController. Google does not give many hits for this problem.
My model layer consists of two class (both of which are appropriately KVC compliant). The first is a model which represents a single column title, it has one property title,
// A model class representing the column title of single NSTableColumn
#interface ColumnTitle : NSObject
#property NSString *title;
+ (ColumnTitle*) columnTitleWithTitle:(NSString*) aString;
#end
The second a model object which represents an ordered group of ColumnTitle objects,
// Class representing an order collection of model items
#interface TableColumnTitles : NSObject
#property NSMutableArray* columnTitles; // an array of ColumnTitle objects
// These are the KVC array accessors
-(void) insertObject:(ColumnTitle*)columnTitle inColumnTitlesAtIndex:(NSUInteger)index;
- (void)removeObjectFromColumnTitlesAtIndex:(NSUInteger)index;
- (void)replaceObjectInColumnTitlesAtIndex:(NSUInteger)index withObject:(ColumnTitle*)columnTitle;
#end
Note that TableColumnTitles object implements the above array accessors which are required for the bindings. Any suggestions?
Haven't tried that before but what you're actually asking for is using KVC for array indexes. A quick google didn't turn up anything on that issue except some results that indicate it's not (yet) possible (check this)
The easiest work-around I could come up with would be to simply add dedicated properties for the array indexes.. not nice but does the job.
So for a NSMutableArray called myArray and contains objects with title properties of type NSString you'd do something like:
#property (nonatomic, readonly, getter = columnOneGetter) NSString *columnOneString;
(NSString*) columnOneGetter
{
return myArray[0].title;
}
Always assuming of course their number is known in advance and we're not talking 200 columns :-)
I think this may/may not be what you're after, but quick google search landed me here:
http://pinkstone.co.uk/how-to-add-touch-events-to-a-uitableviewfooter-or-header/
edit: i realize this is for mac (not ios) but should be pretty easy to translate if it actually helps.

How do I prevent duplicate code inside 2 drawRect: methods?

I have a few lines of drawing code that are duplicated in two different subclasses. When I move this drawing code to its own class and then call it from within drawRect: it is called but it is never drawn to the screen. What is the right way prevent duplicating code in two different drawRect: methods?
Details: I'm making a custom control by subclassing NSTableView and NSTableCellView. My drawing code needs to be in drawRect: in both of these subclasses.
I created a subclass of NSObject that declares one method. Here is the implementation:
#implementation TNLChartDrawingExtras
- (void)drawDividersInRect:(NSRect)rect startingAtDate:(NSDate *)startDate withZoomFactor:(NSNumber *)zoomFactor {
float pos = 0;
NSDate *currentDate = [startDate copy];
while (pos < rect.size.width) {
//draw the vertical divider
NSBezierPath *linePath = [NSBezierPath bezierPathWithRect:NSMakeRect(pos, 0.0, 1.0, rect.size.height)];
[[NSColor colorWithCalibratedWhite:0.85 alpha:0.5] set];
[linePath fill];
//increment the values for the next day
currentDate = [NSDate dateWithTimeInterval:86400 sinceDate:currentDate]; // add one day to the current date
pos = pos + (86400.0/ [zoomFactor floatValue]);
}
}
In my NSTableView subclass I define a property for this object. Then in awakeFromNib I create an instance of this class:
- (void)awakeFromNib {
self.extras = [[TNLChartDrawingExtras alloc] init];
}
In drawRect: I send this message:
- (void)drawRect:(NSRect)dirtyRect {
// more code here...
[self.extras drawDividersInRect:viewBounds startingAtDate:chart.startDate withZoomFactor:self.zoomFactor];
}
The code is executed but the lines it is supposed to draw don't appear. If I put the code from drawDividersInRect:... in the drawRect: method, it works fine.
My original solution (described in the question) may have worked if I had continued to debug it. However, I think the more important question is what is the right way to approach this problem. Here I solve it by adding category on NSView to the project:
I'm trying to add custom drawing code to both NSTableView and NSTableCellView. Both are subclasses of NSView so I created a category of NSView and added my custom drawing method there. Now I can call my drawing method from both subclasses.
Without see any of your code, it sounds like you are in need of a protocol, which is that same thing as an interface in the java language. Protocols are a series of methods that a group of a few unrelated classes may need to used. For example, in a drawing program like PhotoShop, Rects, Ovals, and Images are all valid objects that can be stored as layers in a .psd document, however, they all share traits like the ability to change object properties in a particular way. An example would be adjusting an objects' opacity or rescale an objects size, etc. Methods that access the objects properties for scaling or functions that can be shared between unrelated objects types call for protocols.
They are essentially .h files that list out the methods. The .m file that defines implementation of the code can store a tag in it's .h file.
// example of a class that acts as a protocol implementor
#interface LayerObject: NSObject <Resizable>
The tag says, "I am a member of the protocol named X, you can find one/some of the methods of protocol X in my .m file." All you would have to do is import the protocol to the desired classes using the following syntax:
// Declare protocol
#protocol Resizable;
// List methods wanted from protocol
- id resizeRect: id layerObject;
to gain the methods defined in the protocol.
Here is a website that describes protocols through an example:
http://agilewarrior.wordpress.com/2012/03/19/simple-objective-c-protocol-example/
Another solution would be to create a class hierarchy that uses an abstract class to put the given drawRect method you are working in. From here you could define the two subclass you are working on as a subclass of the abstract class in which they would inherit the drawRect method code, keeping you from repeating the code in two separate classes.

global NSMutableArray variable xcode

I am making an iPhone application that goes through a set of viewcontrollers that collect data from user input. At the end of the views I encapsulate all of the data in an customized object called GELObject. Now I need to save this data in a NSMutableArray somewhere so that it can be accessed by a tableviewcontroller that is another branch off of the rootviewcontroller. I was thinking a global variable from the tableviewcontroller, but I did some research and I am reading about singleton's in the appdelegate. Some guidance would be greatly appreciated and if you're feeling extra generous a quick explanation of how to make and use singleton's because it is intriguing me.
Thanks!
To manage a singleton you create a global variable (can be restricted to one file's scope with static) with an initial sentinel value of nil, and use a class method to create the singleton on the first call.
For example:
static Something* globalSomething = nil;
#implementation Something
+ (id)
sharedSomething
{
if (! globalSomething)
{
/* can use different initializer if necessary */
globalSomething = [[[self class] allocWithZone:NULL] init];
}
return globalSomething;
}
. . .
#end

Core Data fails to generate primitive accessors

From my understanding of Core Data, all that is necessary for primitive accessors to work is the #dynamic directive for the property name (as well as declaring primitive accessors for that property within the entity implementation).
For some reason, when using the generated primitive accessor the setState: method is not modifying the state property:
- (int)state
{
NSNumber * tmpValue;
[self willAccessValueForKey:#"state"];
tmpValue = [self primitiveState];
[self didAccessValueForKey:#"state"];
return [tmpValue intValue];
}
- (void)setState:(int)value
{
[self willChangeValueForKey:#"state"];
[self setPrimitiveState:[NSNumber numberWithInt:value]];
[self didChangeValueForKey:#"state"];
}
while using the key-value-coding version does modify the state property
- (int)state
{
NSNumber * tmpValue;
[self willAccessValueForKey:#"state"];
tmpValue = [self primitiveValueForKey:#"state"];
[self didAccessValueForKey:#"state"];
return [tmpValue intValue];
}
- (void)setState:(int)value
{
[self willChangeValueForKey:#"state"];
[self setPrimitiveValue:[NSNumber numberWithInt:value] forKey:#"state"];
[self didChangeValueForKey:#"state"];
}
in both cases, I primitive accessors are declared as follows (and as per Apple's example and code generation):
#interface Post (CoreDataGeneratedPrimitiveAccessors)
- (NSNumber *)primitiveState;
- (void)setPrimitiveState:(NSNumber *)value;
#end
I'm a bit at a loss to why this would be. Any help would be greatly appreciated!
After tremendous amounts of head-scratching, debugging, fiddling and guess-and-check, I've finally figured out what the problem is: Core Data primitive accessors AREN'T dynamically generated if you define those attributes as instance variables. I had defined them for debugging purposes (as GBD cannot see the values of properties without defined ivars, it seems), and this prevented primitive accessors from being generated correctly. This is something that Apple should really document in some form. As it's very difficult to discover on one's own. I hope this helps others who've been having the same issue!
I've been looking into this and one of the things discovered is that, contrary to docs, the implementation file generated from the data model does NOT list the primitive dynamic accessors. Other places state that you have to add them yourself. Could that be the issue?
Are you using/modifying the code of an NSManagedObject generated by Xcode? I believe that by default these are generated as "commented" out by an #if 0 directive.
Just wanted to say that I am having the same problem and had to switch to setPrimitiveValue and primitiveValueForKey based on your comment here. It bothers me that the default implementation does not work. Of note in my case is that I am subclassing another NSManagedObject. Not sure if that's your case as well.

How to subclass AtlasSpriteManager in Cocos2d?

I need to create some compound sprites that will all move and rotate together. Since it's possible to change the position and rotation of an AtlasSpriteManager I've been trying to subclass so I can create a bunch of shortcuts like
CompoundSprite *cSprite = [CompoundSprite spriteManagerWithFile:#"sprites.png"];
[cSprite makeComplexSprite];
internally, it looks a little like this
-(void)makeComplexSprite
{
AtlasSprite *sp1 = [[AtlasSprite spriteWithRect:CGRectMake(0, 0, 64, 64)
spriteManager:self] retain];
AtlasSprite *sp2 = [[AtlasSprite spriteWithRect:CGRectMake(0, 0, 64, 64)
spriteManager:self] retain];
[self addChild:sp1];
[self addChild:sp2];
[sp1 setPosition:CGPointMake(0,0)];
[sp2 setPosition:CGPointMake(64,0)];
}
However, when I run the applications, It crashes with the following exception
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[AtlasSpriteManager makeComplexSprite]: unrecognized selector sent to
instance 0x107e1c0
Also, if I remove all the code inside 'MakeComplexSprite' and make it do nothing, I also get the same problem.
It's looking like AtlasSpriteManager just doesn't like to be sub classed. Is this the case? If so, why, and how could I work around it?
UPDATE:
I've found a workaround, by creating an NSObject that contains an atlasSpriteManager. It does the trick, but I would still like to subclass AtlasSpriteManager if possible. I appear to be implementing this exaclty as you describe. I'm creating an instance like this
CompoundSprite *cSprite = [CompoundSprite spriteManagerWithFile:#"file.png"];
[cSprite makeBox];
which... now I think about it, means that cSprite is still an AtlasSpriteManager since that's what is being returned. hmmmm. Ho do I change that?
Implement your own spriteManagerWithFile: or compoundSpriteWithFile: in CompoundSprite, which will return an instance of CompoundSprite.
Edit:
Or, you can do something like
[[ComplexSprite alloc] makeComplexSprite];
But then you need to do the 'spriteManagerWithFile:' part also. Like:
-(id)makeComplexSpriteWithFile:(NSString*)file
{
if (! (self = [super initWithSpriteManager:..capacity:..]))
return nil;
// do your ComplexSprite specific initializing here..
return self;
}
The runtime error you are seeing indicates that your program has tried to send the makeComplexSprite message to an object, but no such method has been defined for that object.
You appear to be sending the makeComplexSprite message to an instance of AtlasSpriteManager instead of an instance of your custom CompoundSprite class. Your example code looks correct, so how are you doing the subclassing? It should look something like this:
CompoundSprite.h:
#interface CompoundSprite : AtlasSpriteManager
{
}
- (void)makeComplexSprite;
#end
CompoundSprite.m:
#interface CompoundSprite
- (void)makeComplexSprite
{
...
}
#end
If you do have the subclassing set up properly, make sure you are actually calling makeComplexSprite on an instance of CompoundSprite and not some other object by accident.
Also:
Your code sample has a memory leak. You are creating two autoreleased sprites, then retaining them (which means your class takes ownership of them), and never releasing them. Since the AddChild: method will automatically retain the objects, you can simply lose the retain calls, and everything will be good.

Resources