Reputation: 649
So I was having issues where I had circular dependencies and so I am trying to implement forward declaration. I have three classes (logger, api, helpers), all of which are singleton objects. I have one controller class (globalclass), that has properties linking to the three classes.
Here is my code:
includes.h:
#import "globalclass.h"
#import "logger.h"
#import "api.h"
#import "helpers.h"
globalclass.h:
@class logger
@class api
@class helpers
@interface globalclass : NSObject
+ (id) sharedGlobal;
- (id) init;
...
@property (nonatomic, strong) logger *log;
@property (nonatomic, strong) api *remote;
@property (nonatmoic, strong) helpers *utils;
...
logger/api/helpers.h templates:
@class globalclass
@interface logger : NSObject
+ (id) sharedLogger;
- (id) init;
...
@property (nonatomic, strong) globalclass *gc;
...
globalclass.m:
#import "includes.h"
@implementation globalclass
/*
* Singleton Class
*/
+ (id) sharedGlobal
{
static globalclass *sharedGlobalClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGlobalClass = [[self alloc] init];
});
return sharedGlobalClass;
}
/*
* Init
*/
- (id) init
{
self = [super init];
if (!self) return nil;
// Logging
self.logger = [logger sharedLogger];
...
return self;
}
logger/api/helpers.m template:
#import "includes.h"
@implementation logger
/*
* Singleton Class
*/
+ (id) sharedLogger
{
static logger *sharedLog = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedLog = [[self alloc] init];
});
return sharedLog;
}
/*
* Init
*/
- (id) init
{
self = [super init];
if (!self) return nil;
// Global Class
self.gc = [GlobalClass sharedGlobal];
...
return self;
}
Then, in my AppDelegate, I have a property to the global class and am doing this:
self.gc = [GlobalClass sharedGlobal];
However, it seems that everytime I boot up my app, it stalls and is automatically terminated because it takes too long to boot up.
Am I thinking about forward globals incorrectly?
The app builds fine.
Any help would be appreciated.
Thanks.
Upvotes: 1
Views: 42
Reputation: 12015
You have a deadlock, because the dispatch_once block in sharedGlobal
is (via the global class init) invoking sharedLogger
, which itself is invoking sharedGlobal
(via the logger class init).
Since everything is singletons, there are a few approaches you could take to avoid this issue. Here are two:
A. Replace any self.log
usages in the global class with [logger sharedLogger]
, and replace any self.gc
usages in the logger class with [globalclass sharedGlobal]
. You can get rid of these properties entirely. dispatch_once
is very fast after the first invocation, so performance is not a reason to store reference to singletons as properties (though you could conceivably have other reasons)
B. Keep the log
and gc
properties, but make them readonly properties with custom getters:
@property (nonatomic, readonly) globalclass *gc;
// implementation:
- (globalclass *)gc
{
return [globalclass sharedGlobal];
}
@property (nonatomic, readonly) logger *log;
// implementation:
- (logger *)log
{
return [logger sharedLogger];
}
Personally I would choose A.
Both of these alternatives eliminate any references to the singleton accessors from the init methods, which gets rid of the deadlock.
Upvotes: 3