global NSMutableArray variable xcode - 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

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.

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.

OCMock with Core Data dynamic properties problem

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{};

Is this the right way to add items to NSCombobox in Cocoa?

I'm Delphi programmer and very new to Cocoa.
at first I tried this :
-(void)awakeFromNib
{
int i;
NSString *mystr;
for (i=1;i<=24;i++)
{
[comboHour addItemWithObjectValue:i];
}
}
But it didn't work. Then I tried to search on Google but no luck.
After experimenting about 30 min, I come with this:
-(void)awakeFromNib
{
int i;
NSString *mystr;
for (i=1;i<=24;i++)
{
mystr = [[NSString alloc]initWithFormat:#"%d",i];
[comboHour addItemWithObjectValue:mystr];
//[mystr dealloc];
}
}
My questions are:
Is this the right way to do that ?
Do I always need to alloc new
NSString to change its value from
integer ?
When I uncomment [mystr dealloc],
why it won't run ?
Does it cause memory leak to alloc
without dealloc ?
Where can I find basic tutorial like
this on internet ?
Thanks in advance
Do I always need to alloc new NSString to change its value from integer ?
Generally yes; however, there are more convenient ways to create strings (and many other types of objects) than using alloc and init (see autorelease pools below)
You can pass any Objective-C object type to addItemWithObjectValue:, including NSString and NSNumber objects. Both classes have a number of convenient class methods you can use to create new instances, for example:
for (int i = 0; i < 24; ++i)
{
[comboHour addItemWithObjectValue:[NSNumber numberWithInt:i]];
}
When I uncomment [mystr dealloc], why it won't run ?
Never call dealloc. Use release instead.
Cocoa objects are reference counted, like COM objects in Delphi. Like COM, you call release when you're finished with an object. When an object has no more references it is automatically deallocated.
Unlike COM, Cocoa has "autorelease pools", which allows you to, for example, create a new NSString instance without having to worry about calling release on it.
For example: [NSString stringWithFormat:#"%d", 123] creates an "autoreleased" string instance. You don't have to release it when you're done. This is true of all methods that return an object, except new and init methods.
Does it cause memory leak to alloc without dealloc ?
Yes, unless you're using garbage collection.
Where can I find basic tutorial like this on internet ?
See Practical Memory Management
The correct way is:
-(void)awakeFromNib
{
int i;
for (i=1;i<=24;i++)
{
NSString *mystr = [[NSString alloc]initWithFormat:#"%d",i];
[comboHour addItemWithObjectValue:mystr];
[mystr release];
}
}
You can use NSNumber instead of NSString, which might be preferable depending on your context.
You do need to create a new object everytime, because addItemWithObjectValue: is expecting an object rather than a primitive.
You can create a new object (e.g. `NSString), via two methods:
Using alloc/init, like how you did it initially. Such initializations require the release of the object once it isn't required anymore in the allocation scope, using release rather than dealloc.
Using stringWithFormat: factory methods that use auto release pool to release themselves "automatically". The code would look like:
-(void)awakeFromNib
{
int i;
for (i=1; i <= 24; i++) {
NSString *s = [NSString stringWithFormat:#"%d", i];
[comboHour addItemWithObjectValue:s];
}
}
However, it is recommended not to use such construction within loops.
For memory issues, check out the Memory Management Programming Guide for Cocoa
Based on the code you posted and your stated experience level, I recommend going through Apple's Currency Converter tutorial if you haven't already. It's the standard Cocoa tutorial every beginner should read. Fundamentals like interacting with IBOutlets are covered.

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