I wanted to create a counter that updates by one, every time it satisfied a condition in the if block of my code. To achieve this, i implemented a single tone instead of defining a global variable
In .h file………
#interface MONObject : NSObject {
int *counterplus;
}
#property(nonatomic) int *counterplus;
+(MONbject*) sharedinstance;
#end
In the .m file
static MON object * sharedinstance;
#implementation MONbject;
#synthesize counterplus;
+(MONbject*)sharedinstance
{
if(!sharedinstance){
sharedinstance=[[MONObject alloc]init];
}
return sharedinstance
}
-(MONObject*) int
{
self=[super init];
if(0!=self){
counterplus=0;
}
return self;
}
#end
I call the above as…
if(condition){
[MONObject sharedinstance].counterplus++;
}
when i try to print the value of it using NSLog, program stops and give this error
“single stepping until exit from function objc_msgSend, which has no line number informatiopn. warning remote failure reply: E37
I have no clue at all. I tried to used a global variable by defining it as extern and tried to
increment. But it give the same error.
Is there any way to achieve this? Can you please point me the error in it.
It will be -
#property(nonatomic) int counterplus;
instead of -
#property(nonatomic) int *counterplus;
For Logging int values, use -
NSLog(#"%d", counterplus);
it shud be
#interface MONObject : NSObject {
int counterplus;
}
#property(nonatomic, assign) int counterplus;
+(MONbject*) sharedinstance;
#end
hope it helps. happy coding :)
Related
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.
Why does this code cause an error in XCode? (Use of undeclared ideatifier '_maxConcurrentRequestCount')
#interface HTTPKit : NSObject
#property (nonatomic) NSInteger maxConcurrentRequestCount;
#end
#implementation HTTPKit
- (void)setMaxConcurrentRequestCount (NSInteger)maxConcurrentRequestCount {
}
- (NSInteger)maxConcurrentRequestCount {
if (!_maxConcurrentRequestCount) {
_maxConcurrentRequestCount = 1;
}
return _maxConcurrentRequestCount;
}
#end
Please help me resolve this problem.
why we must use code below to fixed it?
#synthesize maxConcurrentRequestCount = _maxConcurrentRequestCount;
If you override the default getter and setter of a property then the property won't be automatically synthesized and no iVar will be created to back the property.
You can either manually synthesize the property like you said or create your own iVar:
#interface HTTPKit : NSObject {
NSInteger _maxConcurrentRequestCount;
}
...
#end
I have a subclass of NSObject. In this class I have an NSUInteger declared like this:
#interface Deck : NSObject
- (id)initDecks:(NSUInteger)decks;
- (Card *)drawCard;
#property (nonatomic, assign) NSUInteger drawnCards;
In my implementation file, I have the following code:
#import "Deck.h"
#implementation Deck
- (id)initDecks:(NSUInteger)decks {
self = [super init];
if (self) {
self.drawnCards = 1;
}
return self;
}
- (BJCard *)drawCard {
self.drawnCards++;
return nil;
}
The number assigned to the NSUInteger (drawnCards) in the init method is set correctly, however, I am not able to change it later. I get no warnings or crashes in Xcode, but the number remains unchangeable. I have tried to do self.drawnCards++ and self.drawnCards = 10 etc, but nothing works. Any idea what might be wrong with my code? I am checking the value with:
NSLog(#"Value: %tu", self.drawnCards);
I believe the problem here is the objectiveC dot syntax. Because you are doing . with an object this is the equivalent to doing [self drawnCards]++ method call. The result of the method is incremented, not the drawnCards ivar. To do what you want you'll either need to do _drawnCards++ (access the iVar directly), or you'll need to do [self setDrawnCards:self.drawnCards++].
I am adding multiple instances of subclass of NSOperation in a for loop:
NSMutableArray * operations = [[NSMutableArray alloc]initWithCapacity:0];
for(int i =1; i<81;i++){
[operations addObject:[[PDFGenerator alloc]initWithPageNumber:i andPDFParser:pdf]];
}
[_queue addOperations:operations waitUntilFinished: NO];
in PDFGenerator I have a variable that stores the current page number for the operation.
#implementation PDFGenerator
int pageCounter;
In the main method of the PDFGenerator I am logging the current page number and it prints
80 for ALL the operations!
I already fixed by using #property for the current page count,
but I am trying to understand why it's happening. Any ideas?
thanks!
When you just use:
int pageCounter;
You are creating a global variable. Presuming you set this at each iteration, then refer to it in your PDFGenerator methods, it will always use the last value it was set to.
Example:
// Bar.h
#interface Bar : NSObject
FOUNDATION_EXPORT int someThing;
#end
// Bar.m
#implementation Bar
int someThing;
#end
// Foo.m
#import "Foo.h"
#import "Bar.h"
#implementation Foo
- (void)doSomething
{
++someThing;
}
#end
That's totally valid code, and calls to [Foo doSomething] increment someThing.
If you wanted an instance variable, it would look like this:
#interface Bar()
{
int someThing;
}
#end
#implementation Bar
- (void)doSomething
{
++someThing;
}
#end
In this case someThing is defined as an instance variable (not a global variable). It is an accessible part of objects of the Bar.
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.