Objective C - Declaration Error - please explain - ios

#interface Connections()
{
static Connections *this;
}
#end
The above piece of code in .m file throwing compiler error
Type name does not allow storage class to be specified
at the same time when the
static
key word is removed it works well - which so obvious.
Purpose : I want "Connections" instance static and private.
Why is this behavior, please help.

You cannot declare class-level variables in Objective-C classes; instead you need to "hide" them in the implementation file, often giving them static-scope so they cannot be accessed externally.
Connections.m:
#import "Connections.h"
static Connections *_sharedInstance = nil;
#implementation Connections
...
#end
And if this is a singleton, you typically define a class-level accessor to create the singleton upon first use:
+ (Connections *)sharedInstance
{
if (_sharedInstance == nil)
{
_sharedInstance = [[Connections alloc] init];
}
return _sharedInstance;
}
(and you'll need to add the declaration in the .h file):
+ (Connections *)sharedInstance;

Related

Share singleton from Objective C to Swift

I am trying to access an Objective C singleton from Swift, however I only seem to get the initial value created in the init function of the singleton. The flightControllerState object exposed is updated in a delegate function and I can see that the value is properly updated on the Objective C side.
I have followed a few different posts here on SO and also this article on how to call the shared object from Swift. (I should also mention this is running inside a react native project if that may have any impact?)
EDIT updated swift code - I added the wrong line to the init method to grab shared instance - issue is still the same
Objective-C Singleton
#import DJISDK;
#interface RCTBridgeDJIFlightController : RCTEventEmitter<DJIFlightControllerDelegate> {
DJIFlightControllerState *flightControllerState;
}
#property(nonatomic, readonly) DJIFlightControllerState *flightControllerState;
+ (id)sharedFlightController;
#end
#implementation RCTBridgeDJIFlightController
DJIFlightControllerState *flightControllerState;
#synthesize flightControllerState;
+ (id)sharedFlightController {
static RCTBridgeDJIFlightController *sharedFlightControllerInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedFlightControllerInstance = [[self alloc] init];
});
return sharedFlightControllerInstance;
}
- (id)init {
// I also tried this to make sure the shared instance was returned but no luck
//if (sharedFlightControllerInstance != nil) {
// return sharedFlightControllerInstance;
//}
if (self = [super init]) {
flightControllerState = nil;
}
return self;
}
-(void)flightController:(DJIFlightController *)fc didUpdateState:(DJIFlightControllerState *)state {
flightControllerState = state;
}
#end
Swift class calling singleton and accessing values
class VirtualStickController {
var flightControllerSharedInstance: RCTBridgeDJIFlightController
override init() {
self.flightControllerSharedInstance = RCTBridgeDJIFlightController.sharedFlightController()
}
func getFlightControllerState() {
if let state = flightControllerSharedInstance.flightControllerState {
print("FLIGHT CONTROLLER STATE: \(state)") // always null
} else {
print ("NULL")
}
}
DJIFlightControllerState *flightControllerState;
#synthesize flightControllerState;
There is no need to use #synthesize for properties in (modern) Objective-C except in special circumstance.
The property flightControllerState is an instance property and will be synthesised (with or without the #synthesize) using a hidden instance variable for its storage.
The variable flightControllerState is a global variable, it happens to have the same name as the property but has no connection whatsoever with it.
At a guess you are changing the global variable in Objective-C and expecting to see the result in Swift via the property, you won't.
Remove the global variable and then check the rest of your code.
Apart from that your code produces a valid shared instance which can be shared between Objective-C and Swift and changes made in one language will be visible in the other.
HTH
Regarding the titular question about how to access an Objective C singleton from Swift, I would recommend an alternative. Modern convention is to declare your sharedFlightController as a class property and declare init as NS_UNAVAILABLE:
#interface RCTBridgeDJIFlightController : NSObject
...
#property (nonatomic, readonly, class) RCTBridgeDJIFlightController *sharedFlightController;
- (instancetype)init NS_UNAVAILABLE;
#end
The implementation would implement a getter for this class property:
#implementation RCTBridgeDJIFlightController
+ (instancetype)sharedFlightController {
static RCTBridgeDJIFlightController *sharedFlightControllerInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedFlightControllerInstance = [[self alloc] init];
});
return sharedFlightControllerInstance;
}
...
#end
Now, your Swift code can reference RCTBridgeDJIFlightController.shared, as is the convention with Swift singletons.
Regarding why you are receiving a nil for the status, there are one of two possible problems:
You Objective-C code has confusing combination of explicitly defined ivars, manual synthesis, and global variables. (See below.)
I would also suggest that you confirm whether flightController:didUpdateState: is ever getting called at all. (I don't see you ever setting the delegate of the flight controller.) Add a breakpoint or NSLog statement in that method and confirm.
On the first issue, above, I would suggest:
You should not use those commented lines in your init method. If you want to make sure that your singleton object is used, then declare init as NS_UNAVAILABLE.
Given that all your init method is doing is updating flightControllerState to nil, you can remove it entirely. In ARC, properties are initialized to nil for you.
You should not declare explicit ivar in your #interface. Let the compiler synthesize this automatically for you.
You should not #synthesize the ivar in your #implementation. The compiler will now automatically synthesize for you (and will use an appropriate name for the ivar, adding an underscore to the property name.
You should not declare that global in your #implementation.
If you want to use this sharedFlightController from Swift, you should define it to be a class property, not a class method. I know that that article suggested using a class method, but that really is not best practice.
Thus:
// RCTBridgeDJIFlightController.h
#import <Foundation/Foundation.h>
// dji imports here
NS_ASSUME_NONNULL_BEGIN
#interface RCTBridgeDJIFlightController : NSObject
#property (nonatomic, readonly, nullable) DJIFlightControllerState *flightControllerState;
#property (nonatomic, readonly, class) RCTBridgeDJIFlightController *sharedFlightController;
- (instancetype)init NS_UNAVAILABLE;
#end
NS_ASSUME_NONNULL_END
And
// RCTBridgeDJIFlightController.m
#import "RCTBridgeDJIFlightController.h"
#interface RCTBridgeDJIFlightController ()
#property (nonatomic, nullable) DJIFlightControllerState *flightControllerState;
#end
#implementation RCTBridgeDJIFlightController
+ (instancetype)sharedFlightController {
static RCTBridgeDJIFlightController *sharedFlightControllerInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedFlightControllerInstance = [[self alloc] init];
});
return sharedFlightControllerInstance;
}
- (void)flightController:(DJIFlightController *)fc didUpdateState:(DJIFlightControllerState *)state {
NSLog(#"State updated");
self.flightControllerState = state;
}
#end
The end result is that you can now use it like so:
class VirtualStickController {
func getFlightControllerState() {
if let state = RCTBridgeDJIFlightController.shared.flightControllerState {
print("FLIGHT CONTROLLER STATE: \(state)")
} else {
print("NULL")
}
}
}
Note, because the sharedFlightController is now a class property, Swift/ObjC interoperability is smart enough so the Swift code can just reference shared, as shown above.

instance variables in objective c .m file

In Objective c, what is the differences between instance variables var1 and var2 showing below?
(This code is in one .m file, does it make any difference if the #interface is in a header file & #implementation is in implementation file? I mean any difference comparing with that in one file regarding to the two instance variables.)
#interface MyService {
NSString *var1;
}
#end
#implementation MyService {
NSString *var2;
}
#end
The difference between them is visibility. The variable defined in the #interface section is visible to any code which imports the interface. The variable declared in the #implementation section is only visible to code within the class implementation.
If the #interface is declared in the implementation file, it will act, for all practical purposes, the same as declaring it in the #implementation section.
Instance variables declared in the implementation are implicitly
hidden (effectively private) and the visibility cannot be changed -
#public, #protected and #private do not produce compiler errors (with
the current Clang at least) but are ignored.
you can found it here
I have deep searched for your question.Well asked Leem.fin brother.I tried sample one
#import "SecondViewController.h"
#interface SecondViewController ()
{
NSString *variableOne;
}
#end
#implementation SecondViewController
{
NSString *variableTwo;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setValueToString];
NSLog(#"The variable One is - %#",variableOne);
NSLog(#"The variable Two is - %#",variableTwo);
}
-(void)setValueToString
{
variableOne = #"iOS";
variableTwo = #"iPhone";
}
The printed results are
The variable One is - iOS
The variable Two is - iPhone
But when I tried to access these in Class method
+(void)changeStrings
{
variableOne = #"iPad"; //I get error here
variableTwo = #"iMac"; //I get error here
}
The error shows
Instance variable 'variableOne' accessed in class method
Instance variable 'variableTwo' accessed in class method
From above code I understood
Both are instance variables
That can be accessed only in instance methods
There is no difference between them
So Where to put
Difference between them
Difference between putting variable inside interface and implementation

Accessing a class variable from different a class

A very common, generic question but it seems that everybody has it's own opinion about accessing variables that belong in another class. What I want is to use boolean variable in class2 to perform a statement. Example of what I want is:
Class1.h
#Interface Class1{
bool boolean;
}
#Property (nonatomic, retain) bool boolean;
Class1.m
#synthesize boolean;
Class2.m
if(class1.boolean == YES){
Do Something
}
The if statement is class2 doesn't seem to work, as I tried to print the boolean value in class2 and all it returns is false. I want to get the current value of class1 boolean variable and use it in class 2 without initialising it.
Looking at your question, it seems you want to create an instance of 'Class1' in another class, get the properties value to be presented there.
In that case, whenever you instantiate 'Class1', it comes with the initial values. That means the values will be 'null' for sure. If you want to get the changed value, you need to create 'Class1' as Singleton class, where, this class will be instantiated once in the whole application. Means change the value of 'boolean1' in any class, and get the same value in another, whenever or wherever you want.
But again, it totally depends on how you want to use the whole thing.
Singleton example:
// Class1.h
#interface Class1 : NSObject
/**
* A boolean property
*/
#property (nonatomic, strong) BOOL *boolean;
// Class1.m
#implementation Class1
// This is actual initialisation of the class instance.
+ (Class1 *)sharedInstance {
static Class1 *sharedInstance = nil; //static property, so that it can hold the changed value
// Check if the class instance is nil.
if (!sharedInstance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// If nil, create the instance, using dispatch_once, so that this instance never be created again. So, if needed, app will use the existing instance.
sharedInstance = [[super allocWithZone:NULL] init];
// custom initialisation if needed
});
}
return sharedInstance;
}
// So that, if somebody uses alloc and init, a new instance not created always.
// Rather use existing instance
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
// So that, if somebody uses alloc and init, a new instance not created always.
// Rather use existing instance
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Now updating and using the value.
//Class2.m
#import "Class1.h"
Class1 *myinstance = [[Class1 alloc] init];
myinstance.boolean = YES;
Getting the value on another class
//Class3.m
#import "Class1.h"
Class1 *myinstance = [[Class1 alloc] init];
if(myinstance.boolean == YES){
Do Something
}

Set a global variable with a local variable

I got this global variable
define AN_MOBILE_HOSTNAME #"(hostname).mob"
And I want to change the hostname with a segmented control variable, that defines different regions (Europe-USA-Australia)
Thanks
Sorry for my ignorance, im a begginer
You can't change Pre-Processor macros after compile time. You are going to need to set a global NSString for what you want accomplished.
.h
extern NSString *AN_MOBILE_HOSTNAME;
#interface SomeClass
{
}
#end
.m
NSString *AN_MOBILE_HOSTNAME;
#implementation SomeClass
-(id)init
{
//Do the if(self) stuff
{
AN_MOBILE_HOSTNAME = #"(hostname).mob";
}
}
-(void)FunctionToChangeStuff:(NSString*)somethingElse
{
AN_MOBILE_HOSTNAME = somethingElse;
}
#end
Or you could make the object a class variable if you have a singleton class that your program knows about.

Appdelegate Variable in storyboard

I used to declare variale in appdelegate and make it as sharable in all the classes (If the variable is global ) .
appDelegate = (StoryAppDelegate*)[[UIApplication sharedApplication]delegate];
this was the code am using normally to access appdelegate variable. Now am trying a story board application and its not working for me . while declaring appdelegate it shows an error "Unknown type name StoryAppDelegate".
StoryAppDelegate*ss;
this is the code am using .
Any help appreciated .
Just don't use the app delegate. That isn't what it's for.
Instead, create a specific class to own the responsibility + knowledge, make it a singleton and have all classes that require it get it via it's 'sharedController' (or whatever you call it) class method.
Or use a 'constants' file with a static variable or something (just not the app delegate).
Storyboard is used only for design, not changes to the code.
For that, you'd use:
AppDelegate *app;
in the header file of the view's controller.
And in the implementation file,
app=(AppDelegate *)[[UIApplication sharedApplication]delegate];
Then you can just use app.yourVariable
I would recommend using a singleton instance of your global variable as they have bailed me out of your exact situation multiple times. Here is an example I'm currently using to implement a singleton. This methodology is also ARC-safe as well
mySingleton.h
#import <Foundation/Foundation.h>
#interface mySingleton : NSObject {
}
+ (NSMutableDictionary *) myMutableDict;
#end
mySingleton.m
#import "mySingleton.h"
#implementation mySingleton
+ (NSMutableDictionary *)myMutableDict
{
static NSMutableDictionary *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[NSMutableDictionary alloc]init];
});
return singletonInstance;
}
#end
As long as you include mySingleton.h in all of your view controllers you can access the data via [mySingleton myMutableDict]. For example: [[mySingleton myMutableDict] setObject:myObject forKey:myKey]; This will of course work with any object type.
It seems the case of circular dependency.
use #class StoryAppDelegate;
instead of
#import "StoryAppDelegate.h"
in your header file.

Resources