Accessing changeable values in a singleton? - iphone

First off, I come from Lua, don't blame me for being global variable minded lol. So, I've been reading up on how to use this whole "Singleton system" and I'm not sure if I'm completely missing the point or if I'm just implementing it incorrectly?
The goal of my code is to create a way for multiple files to access a variable that holds the size of an array in a specific file. Here is my singleton:
.h
#import <Foundation/Foundation.h>
#interface GlobalVariables : NSObject
{
NSNumber *currentGameArrayCount;
BOOL *isGamePaused;
}
#property (nonatomic, readwrite) NSNumber *currentGameArrayCount;
#property (nonatomic, readwrite) BOOL *isGamePaused;
+ (GlobalVariables *)sharedInstance;
#end
.m
#import "GlobalVariables.h"
#implementation GlobalVariables
#synthesize currentGameArrayCount, isGamePaused;
static GlobalVariables *gVariable;
+ (GlobalVariables *)sharedInstance
{
if (gVariable == nil) {
gVariable = [[super allocWithZone:NULL] init];
}
return gVariable;
}
- (id)init
{
self = [super init];
if (self)
{
currentGameArrayCount = [[NSNumber alloc] initWithInt:0];
isGamePaused = NO;
}
return self;
}
#end
and in another file with the array I use:
GlobalVariables *sharedData = [GlobalVariables sharedInstance];
NSNumber *tmpArrayCount = [sharedData currentGameArrayCount];
NSInteger tmpCount = [whereStuffActuallyHappens.subviews count]; // Subviews is the array
NSNumber *currentCount = [NSNumber numberWithInteger:tmpCount];
tmpArrayCount = currentCount;
the hope of this code was to get the variable in the singeton (currentGameArrayCount) and set it too what the current array count was (currentCount). Am I incorrectly interpreting the purpose of a singleton? Am I just bad at singletons and didn't set it up correctly? Does anyone know how I could achieve the result of getting my array count to be accesible to all my files?

You have a few issues. Try these changes:
GlobalVariables.h:
#import <Foundation/Foundation.h>
#interface GlobalVariables : NSObject
#property (nonatomic, assign) int currentGameArrayCount;
#property (nonatomic, assign) BOOL gamePaused;
+ (GlobalVariables *)sharedInstance;
#end
GlobalVariables.m:
#import "GlobalVariables.h"
static GlobalVariables *gVariable = nil;
#implementation GlobalVariables
+ (GlobalVariables *)sharedInstance {
if (gVariable == nil) {
gVariable = [[self alloc] init];
}
return gVariable;
}
- (id)init {
self = [super init];
if (self) {
self.currentGameArrayCount = 0;
self.gamePaused = NO;
}
return self;
}
#end
Now in your other code you can do:
GlobalVariables *sharedData = [GlobalVariables sharedInstance];
int tmpArrayCount = sharedData.currentGameArrayCount;
NSInteger tmpCount = [whereStuffActuallyHappens.subviews count]; // Subviews is the array
sharedData.currentGameArrayCount = tmpCount;

Related

NSCoding and ARC

I'd like to archive my custom objects. ClassA holds a dictionary whose values are instances of ClassB.
Everything looks good ClassA's initWithCoder, and _dictionary is declared strong, but after init returns and I call callMeAfterInit, the _dictionary is empty (not null, a valid empty dictionary).
This ought to be simple, but I haven't used archiving much, so maybe I'm missing something basic. What might cause the dictionary to be emptied after the init returns?
Here's the essential code:
#interface ClassA : NSObject <NSCoding>
#property (strong, nonatomic) NSMutableDictionary *dictionary;
#end
#implementation ClassA
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.dictionary forKey:#"dictionary"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self) {
_dictionary = [decoder decodeObjectForKey:#"dictionary"];
// breakpoint here and I can inspect a good dictionary, full of ClassB values
}
return self;
}
- (void)callMeAfterInit {
NSLog(#"%#", self.dictionary);
// Log output here shows an empty dictionary (valid, but with 0 pairs)
}
#end
#interface ClassB : NSObject <NSCoding>
#property (strong, nonatomic) NSNumber *number;
#property (strong, nonatomic) NSArray *array;
#end
#implementation ClassB
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.number forKey:#"number"];
[encoder encodeObject:self.array forKey:#"array"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self) {
_number = [decoder decodeObjectForKey:#"number"];
_array = [decoder decodeObjectForKey:#"array"];
}
return self;
}
#end
You don't show the code that calls callMeAfterInit, so this is a guess.
More likely than not, you aren't talking to the same instance of ClassA. Did you happen to call [[ClassA alloc] init]; somewhere?

IOS Why does Initialisation fail with _variable but not with self.variable for NSNumber?

I have the following Class:
---- .h file
#import <Foundation/Foundation.h>
#import "MapperProtocoll.h"
#interface ServiceRequest : NSObject {
}
#property (strong, nonatomic) NSString *url;
#property (strong, nonatomic) NSString *postData;
#property (strong, nonatomic) NSNumber *requestId;
#property (strong, nonatomic) id<ServiceMapperDelegate> mapper;
-(id)initWithUrl:(NSString *)url andWithPostdata:(NSString *)postData;
#end
------- .m file
#import "ServiceRequest.h"
#implementation ServiceRequest
#synthesize url = _url, postData = _postData, requestId = _requestId, mapper = _mapper;
-(id)initWithUrl:(NSString *)url andWithPostdata:(NSString *)postData {
if (self = [super init]) {
_url = url;
_postData = postData;
self.requestId = [NSNumber numberWithInt:-1]; // HERE IS THE PROBLEM
}
return self;
}
#end
Why does
self.requestId = [NSNumber numberWithInt:-1];
work but
_requestId = [NSNumber numberWithInt:-1];
throw a runtime error?
The class method [NSNumber numberWithInt:-1] is returning an autoreleased value. When you use the synthesized setter method, the value gets retained by the setter. When you bypass the setter, there is no retain... So as soon as the autorelease pool is drained you have a dangling pointer.

SBJson int parsing

I have a json string:
{"1":{"homeTeam":"Home01","awayTeam":"Away01","homeScore":0,"awayScore":0,"gameID":1},"2":{"homeTeam":"Home11","awayTeam":"Away11","homeScore":0,"awayScore":0,"gameID":2},"3":{"homeTeam":"Home21","awayTeam":"Away21","homeScore":0,"awayScore":0,"gameID":3}}
that I would like to turn into an Objective-C class:
#import <Foundation/Foundation.h>
#interface ScoreKeeperGame : NSObject {
}
#property (nonatomic, retain) NSString *homeTeam;
#property (nonatomic, retain) NSString *awayTeam;
#property (nonatomic, assign) int homeScore;
#property (nonatomic, assign) int awayScore;
#property (nonatomic, assign) int gameID;
- (id) init: (NSString *) homeTeam
awayTeam: (NSString *) awayTeam;
- (id) init: (NSDictionary *) game;
#end
I pass the json in by NSDictionary "game" (the json string represents a hashmap, so the first game is):
{"homeTeam":"Home01","awayTeam":"Away01","homeScore":0,"awayScore":0,"gameID":1}
When I try to use this class:
#import "ScoreKeeperGame.h"
#implementation ScoreKeeperGame
#synthesize homeTeam=_homeTeam, awayTeam = _awayTeam, homeScore = _homeScore, awayScore = _awayScore, gameID = _gameID;
- (id) init: (NSString *) homeTeam
awayTeam: (NSString *) awayTeam
{
self = [super init];
self.homeTeam = homeTeam;
self.awayTeam = awayTeam;
NSLog(#"away: %#", awayTeam);
return self;
}
- (id) init: (NSDictionary *) game
{
self = [super init];
if(self)
{
self.homeTeam = [game objectForKey:#"homeTeam"];
self.awayTeam = [game objectForKey:#"awayTeam"];
self.awayScore = (int) [game objectForKey:#"awayScore"];
self.gameID = [game objectForKey:#"gameID"];
NSLog(#"game awayScore: %d", self.awayScore);
NSLog(#"game gameID: %#", [NSNumber numberWithInt:self.gameID]);
}
return self;
}
#end
The awayScore and gameId are printed as large numbers (maybe pointers)?
I've tried
self.awayScore = [NSNumber numberWithInt: [game objectForKey:#"awayScore"]];
But that didn't seem to work either.
How do I get the value of the int from the game object?
po game produces:
{
awayScore = 0;
awayTeam = Away01;
gameID = 1;
homeScore = 0;
homeTeam = Home01;
}
Thanks!
You have to pull it out as an NSNumber first.
NSNumber *myNum = [game objectForKey:#"awayScore"];
self.awayScore = [myNum intValue];
Doh!
you can try this if you want to get integer value from your JSON response
self.awayScore = [NSNumber numberWithInt: [[game objectForKey:#"awayScore"] intValue]];
as your response would be in nsstring.
iOs 6.0, now it's simply [game[#"awayScore"] intValue]

Not Able to Add Object to NSMutableArray

Hey guys, I have this code within a function inside a class that is a subclass of NSOperation:
//...
#implementation DataLoader
#synthesize addedAnnotations;
#synthesize addedOverlays;
#synthesize loaderFunc;
#synthesize DLDelegate;
//...
-(id)initWithFunction:(LoaderFunc)func withDelegate:(id)delegate {
if (self = [super init]) {
self.addedOverlays = nil;
self.addedAnnotations = nil;
self.loaderFunc = func;
self.DLDelegate = delegate;
return self;
}
return nil;
}
//...
//inside a function
for (ParkingAnnotations *annotation in fetchedObjects) {
ParkingAnnotation *parkingAnnot = [[ParkingAnnotation alloc] init];
workingCoordinate.latitude = [[annotation latitude] doubleValue];
workingCoordinate.longitude = [[annotation longitude] doubleValue];
[parkingAnnot setCoordinate:workingCoordinate];
[parkingAnnot setTitle:[annotation valueForKey:#"lotName"]];
[parkingAnnot setAnnotationType:[annotation iconTypeRaw]];
[self.addedAnnotations addObject:parkingAnnot];//parkingAnnot not added to array here
[parkingAnnot release];
}
//...
Added annotations is an NSMutable array, I have been walking through this code with the debugger and for some reason the parkingAnnot object is not getting added to the array. Here is the relevant header code for the class:
//...
#interface DataLoader : NSOperation {
NSMutableArray *addedAnnotations;
NSMutableArray *addedOverlays;
LoaderFunc loaderfunc;
id <DataLoaderProtocol> DLDelegate;
}
#property (nonatomic, retain) NSMutableArray* addedAnnotations;
#property (nonatomic, retain) NSMutableArray* addedOverlays;
#property (nonatomic) LoaderFunc loaderFunc;
#property (assign) id DLDelegate;
//...
It is an astonishing problem because the function in which I am experiencing the problem was copied from my MapViewController and is essentially the same, but instead of mapView addAnnotation: I am adding to an NSMutable array instead. Any idea of what's up? Thanks in advance!
Where are you actually instantiating the addedAnnotations array? I only see it being assigned nil in your initialize function, maybe it should change to something like:
self.addedAnnotations = [[[NSMutableArray alloc] init] autorelease];

invalid CFArrayRef problem with Singleton object

I've built a singleton object to manage some data in my app
#interface MyCommon : NSObject {
NSArray *quizz;
int iCurrentQuestion;
};
+ (MyCommon *)singleton;
#property (retain) NSArray *quizz;
#property (assign) int iCurrentQuestion;
#end
MyCommon.m
#import "MyCommon.h"
// MyCommon.m:
#implementation MyCommon
static MyCommon * MyCommon_Singleton = nil;
#synthesize iCurrentQuestion;
+ (MyCommon *)singleton
{
if (nil == MyCommon_Singleton)
{
MyCommon_Singleton = [[MyCommon alloc] init];
NSLog(#"allocating MyCommon_Singleton at %#",MyCommon_Singleton);
}
else {
NSLog(#"accessing singleton : %#", MyCommon_Singleton);
}
return MyCommon_Singleton;
}
- (NSArray*) getQuizz{
return quizz;
}
- (void) setQuizz:(NSArray *)array {
quizz = [NSArray arrayWithArray:array];
NSLog(#"setQuizz : %#",quizz);
}
There is no problem for writing the quizz object (setQuizz), however when I try to access it for reading, I get a crash : the quizz looks invalid and Xcode notify me an invalid CFArrayRef
I don't know what's wrong with my code.
You provide a custom setter for quizz but it doesn't comply with how the property is declared.
You're not retaining quizz when you're setting a new value. It's likely to be released just after, leading to a crash when you access it.
You should write
- (void)setQuizz:(NSArray *)array {
if (quizz != array) {
NSArray *tmp = quizz;
quizz = [array retain]; // retain the new value
[tmp release]; // release the old one
}
NSLog(#"setQuizz : %#",quizz);
}
this is way more code than it needs to be. First if you are going to be providing your own method you should declare so in the #property declaration which you didn't. Also your not properly retaining your variables. Additionally you should be using dispatch_once() for a thread safe & fast way to guarantee the singleton is only created once.
#interface MyCommon : NSObject {}
#property(nonatomic, retain) NSArray *quiz;
#property (assign) int iCurrentQuestion;
+ (MyCommon *)singleton;
#end
#implementation MyCommon
#synthesize quiz;
#synthesize iCurrentQuestion;
-(id)init {
self = [super init];
if(self) {
quiz = [[NSMutableArray alloc init];
iCurrentQuestion = 0;
}
return self;
}
+ (MyCommon *)singleton {
static MyCommon *singleton = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
singleton = [[MyCommon alloc] init];
});
return singleton;
}
#end
then you just do
[MyCommon singleton].quiz = //some array