I've got my project written in Objective-C. I am learning about bridging.
I bridged successfully Swift into my Objective-C project. I did some VC pushing between Objective-C VC and Swift VC. Everything works as it supposed to.
However, I created the reference to my Objective-C NetworkManager (I used Singleton pattern) in my Swift file like that:
let networkManager = NetworkManager.sharedManager()
For some reason I cannot use methods from it.
networkManager.getUserInfo() // .getUserInfo() will not appear!
Just to show you how I've created my NetworkManager as a Singleton. I found that solution online and it was quite old, if you have any better solution, I would be more than happy to get some insight:
+ (id)sharedManager {
static NetworkManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(id)init {
if (self = [super init]) {
someProperty = #"Default Property Value";
self.cache = [[NSCache alloc] init];
}
return self;
}
Not sure what is the issue here. Thank you all for the help.
For those who may look for the answer in the future.
I've been advised to not use id type when bridging with Swift. I've changed:
+ (id)sharedManager {
to
+ (NetworkManager *)sharedManager
And now everything works fine.
Related
I'm trying to create a singleton. This group of code is meant to establish a settingsMAnager singleton.
Im trying to allocate it but keep throwing an error
Its throwing the error no visible # interface with NSObject.
Declares the selector 'alloc'
Can someone see what's wrong?
Thanks in advance!
//In my .h file I have
+(settingsManager*)getInstance;
-(void)printSettings;
//In My .m file is----
static settingsManager *theInstance = nil;
//Instance Method
+(settingsManager*)getInstance
{
(theInstance == nil)
{
[[self alloc] init];//Im getting "expression result unused" here
}
return theInstance;
}
-(id)alloc
{
theInstance = [super alloc];<------//getting the big error here
return theInstance;
}
-(id)init
{
if (self = [super init])
{
}
return self;
}
(void)printSettings
{
NSLog(#"Hello");
}
You should never subclass the alloc method. Below is the code to use a singleton:
+ (instancetype)sharedInstance {
static SettingsManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[settingsManager alloc] init];
});
return sharedInstance;
}
And if you're interested in some more reading, I suggest you this link.
I'd also suggest you to read the recommended coding guidelines for objective-c.
instancetype
instancetype is a contextual keyword that can be used as a result type to signal that a method returns a related result type. instancetype, unlike id, can only be used as the result type in a method declaration. More details here.
dispatch_once
As explained here, dispatch_once() is synchronous and allows you to execute a piece of code only once.
This is not the right way to implement a singleton. There are a number of unidiomatic and potentially risky bits in your implementation. However, this error is coming from the fact that alloc is a class method, not an instance method as you've written it here.
(CODE UPDATED) after IOS 7 update, my app is crashing with singleton label (and this happened only in the device)...first time accessing singleton everything it's ok, but second time ClassSingleton is nil. Can anyone help? (before IOS 7 everything was fine...now i get Bad Access Code =1)
I'm using ARC...
thanks
ClassSingleton.h
#property (nonatomic, strong) IBOutlet UILabel *lblResultado;
ClassSingleton.m
#synthesize lblResultado;
__strong static ClassSingleton *pOutClassSingletonReturn = nil;
#pragma mark Singleton Methods
+ (void)initialize
{
pOutClassSingletonReturn = [[super allocWithZone:NULL] init];
pOutClassSingletonReturn.lblResultado = [[UILabel alloc] init];
pOutClassSingletonReturn.lblResultado.backgroundColor = [UIColor clearColor];
pOutClassSingletonReturn.lblResultado.textColor = [UIColor whiteColor];
pOutClassSingletonReturn.lblResultado.textAlignment = NSTextAlignmentRight;
pOutClassSingletonReturn.lblResultado.text = #"0";
}
+ (ClassSingleton*) pOutClassSingletonReturn
{
return pOutClassSingletonReturn;
}
#end
AccessClass.m
#implementation AccessClass
__strong static ClassSingleton *pOutClassSingletonReturn;
- (void)viewDidLoad
{
[super viewDidLoad];
externalsObjects = [NSDictionary dictionaryWithObject:[ClassSingleton pOutClassSingletonReturn] forKey:#"pOutClassSingletonReturn"];
nibOptions = [NSDictionary dictionaryWithObject:externalsObjects forKey:UINibExternalObjects];
[self.nibBundle loadNibNamed:self.nibName owner:self options:nibOptions];
pOutClassSingletonReturn = [ClassSingleton pOutClassSingletonReturn];
pOutClassSingletonReturn.lblResultado.text = #"1";
}
- (IBAction) button: (id) sender
{
pOutClassSingletonReturn.lblResultado.text = #"blabla"; //==>>> Crash second time i press the button
}
You implemented the singleton pattern improperly in modern Objective-C.
In this example, let's call your Singleton class method, sharedInstance. Initialize your singleton as follows:
+ (id)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Then, in the same Singleton Class, put your initialization code in your init method
- (id)init
{
self = [super init];
if (self) {
// Your initialization code goes here
}
return self;
}
You can change the method from init to whatever you want. Just make sure to change the name in the sharedInstance class method.
To call your Singleton in your other classes, simply do the following:
[MySingletonClass sharedInstance]
The first time it's called, the init method in the Singleton will be set (which is obvious, as it's a Singleton).
Try initializing your singleton using the static + (void)initialize method instead.
See: What should my Objective-C singleton look like?
I don't see where you've declared pOutClassSingletonReturn in AccessClass.m, so it's hard to tell if it's a global variable, an instance variable, a reference to the pOutClassSingletonReturn in ClassSingleton.m, or what. But I suspect that the problem isn't so much with the pOutClassSingletonReturn in ClassSingleton.m as it is with the one in AccessClass.m. Make sure that's a strong reference, or at least add it to your view hierarchy in -viewDidLoad.
First i want to thanks to everyone who try to help!
I found the error (singleton was ok...)...the error was
when i concatenate 2 NSString's like that i get an error (further in the singleton):
pOutclassCalculadora.pstrOutParcela1 = [pOutclassCalculadora.pstrOutParcela1 stringByAppendingString: pOutclassCalculadora.pstrOutTeclaSender];
Now i'm doing like that and everything is ok (no bad access):
pOutclassCalculadora.pstrOutParcela1 = [NSString stringWithFormat:#"%#%#",pOutclassCalculadora.pstrOutParcela1,pOutclassCalculadora.pstrOutTeclaSender];
The big question...why this "stringByAppendingString" works in the simulator and in IO6 and crashes in IOS7 (and only in the device)?????
If you are using ARC then try declaring the static to be strong like this:
__strong static ClassSingleton *pOutClassSingletonReturn = nil;
so that ARC knows to retain it for you.
I've created a simple singleton class to hold static data for my projects.
The first time I access this singleton is onEnter method in my Cocos2d scene. However when I try to access it again later in another method (same scene) this singleton is already released. I'm confused, how do I keep my singleton from being deallocated?
Here's my singleton's interface part:
#import <Foundation/Foundation.h>
#interface OrchestraData : NSObject
+(OrchestraData *)sharedOrchestraData;
#property (retain, readonly) NSArray *animalNames;
#end
Implementation:
#import "OrchestraData.h"
#implementation OrchestraData
#synthesize animalNames = animalNames_;
+(OrchestraData*)sharedOrchestraData
{
static dispatch_once_t pred;
static OrchestraData *_sharedOrchestraData = nil;
dispatch_once(&pred, ^{ _sharedOrchestraData = [[OrchestraData alloc] init]; });
return _sharedOrchestraData;
}
-(id)init {
if (self = [super init]) {
animalNames_ = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
}
return self;
}
#end
I'm using my singleton this way:
[[OrchestraData sharedOrchestraData] animalNames];
Update:
I took a fresh look into it with NSZombies enabled, it appears as if my NSArrays were released, not the singleton itself. What do I do?
You must implement your singleton in this way:
1) in .h file of your Singleton Class:
+ (SingletonClass *)instance;
2) in .m file:
+ (SingletonClass *)instance {
static SingletonClass* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
//your init code here
});
return instance;
}
If you want to call your singleton, just call [SingletonClass instance].
If your are interesting what is "dispatch_once_t", read about Grand Central Dispatch:
http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
RE Update:
Your NSArray deallocates because you're using the autorelease initializer arrayWithObjects and you assign it directly to the ivar animalNames_. Therefore it is not retained.
To fix this, assign the array to the property:
self.animalNames = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
Btw, under ARC this wouldn't have been an issue since the ivar would have been a strong (retaining) reference. I don't get tired encouraging anyone to switch to ARC. It's been available for well over a year now and there's absolutely no point in using MRC code anymore! It really pains me to see how developers still don't use the easier, faster, and straightforward option. (rant off) :)
You setup a pointer wherever you need it.
-(void)someMethod {
MySingleton *singleton = [MySingleton sharedSingleton];
singleton.data = YES; //dumb example to show you did something...
}
-(void)someOtherMethod {
MySingleton *singleton = [MySingleton sharedSingleton]; //You have to create a new pointer...
singleton.data = NO; //another dumber example to show you did something...
}
Note: this assumes that you have created a singleton the same way I have... your code might be different therefore causing my answer not to apply...
You need to overwrite the below method inside your singleton class, because in your program, if someone has initialised [[SingletonClass alloc] init] then singleton will have another instance and release it will cause an error.
+ (id)allocWithZone:(NSZone *)zone{
return [[self SingletonClass] retain];
}
- (id)copyWithZone:(NSZone *)zone{
return self;
}
- (id)retain{
return self;
}
There is a strange behavior in my code and I really don't know how to solve it.
I have a Singleton class with this definition:
AppModelLocator.h>
#import <Foundation/Foundation.h>
#interface AppModelManager : NSObject
+ (AppModelManager *)sharedManager;
#end
AppModelLocator.m
#import "AppModelManager.h"
static AppModelManager *instance = nil;
#implementation AppModelManager
#pragma mark - Singletone
#pragma mark
+ (AppModelManager *)sharedManager
{
#synchronized ([AppModelManager class]) {
if (instance == nil) {
instance = [AppModelManager new];
}
}
return instance;
}
+ (id)alloc
{
#synchronized ([AppModelManager class]) {
NSAssert(instance == nil, #"Attempted to allocate the second instance of AppModelManager.");
instance = [super alloc];
return instance;
}
return nil;
}
#end
When I call [AppModelLocator sharedManager]somewhere in my code everything is fine. But when I call the singleton class after a specific line of code it throws me EXC_BAD_ACCESS (code=1, address=0xfffffeec) and refers to return instance in sharedManager definition in the singleton class.
That specific code is initializing a class that create a HTTP request and start sending the request but in the class is not any reference of AppModelLocator or something special. It is a simple creating of NSURLConnection and its delegate methods.
I used similar classes and approach in other applications and they are working fine and I wonder what is wrong with this class. I tried a dozen other ways of creating singleton class but none of them were useful.
Why don't you simply use GCD to instantiate your singleton?
+ (AppModelManager *)sharedManager
{
static AppModelManager* instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[AppModelManager alloc] init];
});
return instance;
}
Finally, I found what was wrong in the code. I made a NSURL instance dynamically and I used 3rd library to encrypt the URL. Something through the encoding caused the crash in special condition but I wonder why the exception raised after calling the singleton class. Anyway the issue was not because of the singleton definition as deanWombourne said.
I'm trying to write a class that I can subclass to have an instant singleton. Here's what I have so far. It works until one of its subclasses calls another via sharedInstance which causes a huge loop that eventually runs out of memory.
Any ideas?
static NSMutableDictionary *sharedInstances = nil;
#implementation Singleton
+ (Singleton*)sharedInstance
{
[Singleton initSharedInstances];
Class myClass = [self class];
Singleton * sharedInstance = [sharedInstances objectForKey:myClass];
#synchronized(myClass)
{
if (sharedInstance == nil)
{
sharedInstance = [[myClass alloc] init];
[sharedInstances setObject:sharedInstance forKey:myClass];
}
}
return sharedInstance;
}
+ (void) initSharedInstances
{
if (sharedInstances == nil)
{
sharedInstances = [[NSMutableDictionary alloc] init];
}
}
#end
Why are you bothering with all this? If you're trying to enforce singleton behavior in the superclass by overriding -retain, -release, -retainCount, and +allocWithZone: then you're doing something completely unnecessary. Far more simple is just to provide a +sharedInstance method and do nothing else. If the user really wants to call +alloc/-init, they can, it just won't do them much good. For examples of this type of singleton in the frameworks, look at NSUserDefaults and NSFileManager (though in the case of the latter, these days Apple actually recommends you ignore the shared instance and alloc/init your own instances of NSFileManager).
In order to do this simple shared instance stuff, all you have to do is, in the singleton class, implement the following:
+ (id)sharedInstance {
static MyClass sharedInstance;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
//sharedInstance = [[MyClass alloc] init];
sharedInstance = [MyClass alloc];
sharedInstance = [sharedInstance init];
});
return sharedInstance;
}
I'm trying to write a class that I can subclass to have an instant singleton. Here's what I have so far. It works until one of its subclasses calls another via sharedInstance which causes a huge loop that eventually runs out of memory.
This sounds like you are describing mutual-recursion. If subclass1 calls subclass2 and subclass2 calls subclass1 then you need to break the loop somewhere, just as with simple self-recursion.
Your sharedInstance itself should not cause infinite recursion unless the init method you invoke itself invokes sharedInstance...