Set a global variable with a local variable - ios

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.

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

Get variable value from another void

I just started programming in XCode and I need your help.
I have two voids; in the first void I create a NSString, and in the second void I need the value of that string, but i don't know how to obtain that value.
This is a shortend version of my .h file
//.h file
-(void)viewDidLoad
{
[self ActionOne];
}
-(IBAction)ButtonClick (id):sender
{
[self ActionTwo];
}
-(void)ActionOne
{
NSString *VarString = #"hello";
}
-(void)ActionTwo
{
NSLog (#"%#", VarString);
}
My problem is that NSLog's output is 'null', I hope someone can help me
You have declared a local variable in ActionOne. It only lives as long as the method is running. For persistent storage, you need an ivar (that's a term used in Objective-C to mean an "instance variable", which is a variable for which there is a separate copy for each object that is an instance of a class). The easiest way to do this is to declare a property, which will create an ivar and methods to access it for reading and writing. In your .h file:
#interface MyViewController: UIViewController
#property (nonatomic, strong) NSString *varString;
// ... method declarations, etc
#end
And then in your .m file:
-(void)actionOne
{
self.varString = #"hello";
}
-(void)actionTwo
{
NSLog(#"%#", self.varString);
}

setting up enum in a singleton within an ios app such that it can be accessed throughout the app

I would like to set up my global constant values within a Constants Singleton class in my iOS app such that any class importing the constants can use those values.
However, after playing around for a few hours with this idea, I am still unable to make it work.
In my Constants.m file
#interface Constants()
{
#private
int _NumBackgroundNetworkTasks;
NSDateFormatter *_formatter;
}
#end
#implementation Constants
static Constants *constantSingleton = nil;
//Categories of entries
typedef enum
{
mapViewAccessoryButton = 999
} UIBUTTON_TAG;
+(id)getSingleton
{
.....
}
I have another class MapViewController where I have a reference to the Constants singleton and Im trying to access the enums like this
myDetailButton.tag = self.constSingleton.UIBUTTON_TAG.mapViewAccessoryButton;
However, this is not working. Im not able to access the UIBUTTON_TAG inside the mapviewcontroller
ANybody have any suggestions?
Thanks
If you want the enum available throughout the app, put the enum definition in the .h file, not the .m file.
Update:
Objective-C doesn't support namespaces and it doesn't support class level constants or enums.
The line:
myDetailButton.tag = self.constSingleton.UIBUTTON_TAG.mapViewAccessoryButton;
should be:
myDetailButton.tag = mapViewAccessoryButton;
assuming you define the UIBUTTON_TAG enum in some .h file.
When you compile an Objective-C app, all values of all enum must have unique names. This is a result of Objetive-C being based on C.
Update 2:
There is one way to get what you want but not with enums. Something like this should work:
Constants.h:
#interface UIBUTTON_TAG_ENUM : NSObject
#property (nonatomic, readonly) int mapViewAccessoryButton;
// define any other "enum values" as additional properties
#end
#interface Constants : NSObject
#property (nonatomic, readonly) UIBUTTON_TAG_ENUM *UIBUTTON_TAG;
+ (id)getSingleton;
// anything else you want in Constants
#end
Constants.m
#implementation UIBUTTON_TAG_ENUM
- (int)mapViewAccessoryButton {
return 999;
}
#end
#implementation Constants {
int _NumBackgroundNetworkTasks;
NSDateFormatter *_formatter;
UIBUTTON_TAG_ENUM *_uiButtonTag;
}
#synthesize UIBUTTON_TAG = _uiButtonTag;
- (id)init {
self = [super init];
if (self) {
_uiButtonTag = [[UIBUTTON_TAG_ENUM alloc] init];
}
return self;
}
// all of your other code for Constants
#end
Now you can do:
myDetailButton.tag = self.constSingleton.UIBUTTON_TAG.mapViewAccessoryButton;
I'm not sure if there is a point to this though.
One way to do this is simply stick it in your precompiled header (.pch) if you aren't going to be changing the enum a lot.

What does "#private" mean in Objective-C?

What does #private mean in Objective-C?
It's a visibility modifier—it means that instance variables declared as #private can only be accessed by instances of the same class. Private members cannot be accessed by subclasses or other classes.
For example:
#interface MyClass : NSObject
{
#private
int someVar; // Can only be accessed by instances of MyClass
#public
int aPublicVar; // Can be accessed by any object
}
#end
Also, to clarify, methods are always public in Objective-C. There are ways of "hiding" method declarations, though—see this question for more information.
As htw said, it's a visibility modifier. #private means that the ivar (instance variable) can only be accessed directly from within an instance of that same class. However, that may not mean much to you, so let me give you an example. We'll use the init methods of the classes as examples, for simplicity's sake. I'll comment inline to point out items of interest.
#interface MyFirstClass : NSObject
{
#public
int publicNumber;
#protected // Protected is the default
char protectedLetter;
#private
BOOL privateBool;
}
#end
#implementation MyFirstClass
- (id)init {
if (self = [super init]) {
publicNumber = 3;
protectedLetter = 'Q';
privateBool = NO;
}
return self;
}
#end
#interface MySecondClass : MyFirstClass // Note the inheritance
{
#private
double secondClassCitizen;
}
#end
#implementation MySecondClass
- (id)init {
if (self = [super init]) {
// We can access publicNumber because it's public;
// ANYONE can access it.
publicNumber = 5;
// We can access protectedLetter because it's protected
// and it is declared by a superclass; #protected variables
// are available to subclasses.
protectedLetter = 'z';
// We can't access privateBool because it's private;
// only methods of the class that declared privateBool
// can use it
privateBool = NO; // COMPILER ERROR HERE
// We can access secondClassCitizen directly because we
// declared it; even though it's private, we can get it.
secondClassCitizen = 5.2;
}
return self;
}
#interface SomeOtherClass : NSObject
{
MySecondClass *other;
}
#end
#implementation SomeOtherClass
- (id)init {
if (self = [super init]) {
other = [[MySecondClass alloc] init];
// Neither MyFirstClass nor MySecondClass provided any
// accessor methods, so if we're going to access any ivars
// we'll have to do it directly, like this:
other->publicNumber = 42;
// If we try to use direct access on any other ivars,
// the compiler won't let us
other->protectedLetter = 'M'; // COMPILER ERROR HERE
other->privateBool = YES; // COMPILER ERROR HERE
other->secondClassCitizen = 1.2; // COMPILER ERROR HERE
}
return self;
}
So to answer your question, #private protects ivars from access by an instance of any other class. Note that two instances of MyFirstClass could access all of each other's ivars directly; it is assumed that since the programmer has complete control over this class directly, he will use this ability wisely.
It important to understand what it means when somebody says that you can't access a #private instance variable. The real story is that the compiler will give you an error if you attempt to access these variables in your source code. In previous versions of GCC and XCode, you would just get a warning instead of an error.
Either way, at run time, all bets are off. These #private and #protected ivars can be accessed by an object of any class. These visibility modifiers just make it difficult to compile the source code into machine code that violates the intent of the visibility modifiers.
Do not rely on ivar visibility modifiers for security! They provide none at all. They are strictly for compile-time enforcement of the class-builder's wishes.

Resources