I am trying to store the reference of the RCTResponseSenderBlock to use it letter
// declaration
#interface AppDelegate()
#property (nonatomic, strong) RCTResponseSenderBlock callback;
#end
// exporting
#implementation AppDelegate
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(callback: (RCTResponseSenderBlock)callback) {
self.callback = callback;
}
- (void)sedEvent {
dispatch_async(dispatch_get_main_queue(), ^{
self.callback(#[#("ScanningComplete")]); // application crash here
});
}
// implementing delegate
#interface AppDelegate : EXAppDelegateWrapper <RCTBridgeDelegate, RCTBridgeModule>
-(void) sedEvent;
#end
But the application is crashing when self.callback(#[#("ScanningComplete")]); is executed
Related
I have a hierarchy of UIViews. They are all handled differently but if nested I can not get my setDelegate of super to fire. I receive a crash exception [ThirdClass setDelegate:] unrecognized selector sent to instance. This actually happens no matter what (subclass) i use SecondClass or ThirdClass, but If I use (FirstClass) everything works as it should but any subclassing of the delegate it does not recognize the call. I have simplified what I am doing below which if I call out my first class separately inside my MainControlInterface everything works as it should. Im sure Im doing something wrong here but can't determine what that is, If anyone could help that would be greatly appreciated, thank you.
#protocol FirstClassDataSource, FirstClassDelegate;
#interface FirstClass : UIView
#property (nonatomic, weak_delegate) __nullable id<FirstClassDataSource> dataSource;
#property (nonatomic, weak_delegate) __nullable id<FistClassDelegate> delegate;
#end
#protocol FirstClassDataSource <NSObject>
- (NSInteger)doSomething:(FirstClass *)class;
#optional
- (NSInteger)doSomethingElse:(FirstClass *)class;
#end
#protocol FirstClassDelegate <NSObject>
#optional
- (void)handleMoreDelegateMethods:(FirstClass *)class;
#end
#implementation FirstClass
- (void)setDataSource:(id< FirstClassDataSource >)dataSource
{
if (_dataSource != dataSource)
{
_dataSource = dataSource;
if (_dataSource)
{
[self reloadData];
}
}
}
- (void)setDelegate:(id< FirstClassDelegate>)delegate
{
if (_delegate != delegate)
{
_delegate = delegate;
if (_delegate && _dataSource)
{
[self setNeedsLayout];
}
}
}
#end
#interface SecondClass : FirstClass
-(id)sencondClassesPrivateMethods;
#end
#interface ThirdClass : secondClass
-(id)thirdClassPrivateMethods;
#end
#interface MainControlInterface : UIView <FirstClassDataSource, FirstClassDelegate>
-(ThirdClass *)thirdClass;
#end
#implementation MainControlInterface
-(void)didMoveToSuperview{
ThirdClass *mythirdSubClass = [self thirdClass];
mythirdSubClass.delegate = self;
mythirdSubClass.dataSource = self;
}
#end
I can't tell what you're doing wrong either. But, your sample code will not compile. (It's full of typos.) I have tried to recreate what you're talking about, simplifying it further. (I've used CodeRunner, a macOS app which facilitates this sort of thing.)
#import <Foundation/Foundation.h>
#protocol FirstClassHandling <NSObject>
- (void)doTheThing;
#end
#interface FirstClass : NSObject
#property (nonatomic, weak) id<FirstClassHandling> delegate;
- (void)doSomething;
#end
#implementation FirstClass
- (void)doSomething
{
NSLog(#"First class.");
if ([[self delegate] respondsToSelector:#selector(doTheThing)]) {
[[self delegate] doTheThing];
}
}
#end
#interface SecondClass : FirstClass
#end
#implementation SecondClass
- (void)doSomething
{
NSLog(#"Second class");
[super doSomething];
}
#end
#interface Handler : NSObject <FirstClassHandling>
#end
#implementation Handler
- (void)doTheThing
{
NSLog(#"Doing my thing!!!");
}
#end
int main(int argc, char *argv[])
{
#autoreleasepool {
Handler* handler = [[Handler alloc] init];
SecondClass* sc = [[SecondClass alloc] init];
sc.delegate = handler;
[sc doSomething];
}
}
The above does not crash. Please fix your example code.
I want to provide methods used in several view controllers called in my delegate methods.
For example, I have some CloudKit functionality (I've added this to my own framework, but I don't think thats important), where I want to provide some crash logging.
Previosuly I had a crashLog function in each of my view controllers, which worked fine, but I have a lot of duplicate code.
Therefore I'd like to produce a category with these methods instead.
However I'm having difficulty getting my delegate methods to see these category methods.
Here's my code..
UIViewController+CloudKitDelegates.h
#interface UIViewController (CloudKitDelegates) <iCloudDBDelegate>
#property (weak,nonatomic) id<iCloudDBDelegate>iCloudDBDelegate;
-(void)crashLog:(NSString*)message, ...;
#end
UIViewController+CloudKitDelegates.m
#import "UIViewController+CloudKitDelegates.h"
#implementation UIViewController (CloudKitDelegates)
#dynamic iCloudDBDelegate;
-(void)crashLog:(NSString*)message, ...
{
va_list args;
va_start(args, message);
NSLog(#"%#", [[NSString alloc] initWithFormat:message arguments:args]);
va_end(args);
}
#end
h file - my calling view controller (e.g. My View Controller)
#import "UIViewController+CloudKitDelegates.h"
m file - delegate method
-(NSString*)getDBPath
{
[self.iCloudDBDelegate crashLog: #"testing"];
From this call I'm getting an error ...
'NSInvalidArgumentException', reason: '-[MyViewController crashLog:]:
unrecognized selector sent to instance
The error is showing that my calling view controller called MyViewController doesn't have the crashLog method, which I have in my category.
Any ideas where I'm going wrong ?
The problem: identical method crashLog: in multiple classes, for example
#interface ViewController : UIViewController
#end
#implementation ViewController
- (void)someMethod {
[self crashLog:#"error"];
}
-(void)crashLog:(NSString *)message {
NSLog(#"%#", message);
}
#end
Solution A: move crashLog: to a common superclass (or a category on superclass UIViewController)
#interface CommonViewController : UIViewController
-(void)crashLog:(NSString *)message;
#end
#implementation CommonViewController
-(void)crashLog:(NSString *)message {
NSLog(#"%#", message);
}
#end
#interface ViewController : CommonViewController
#end
#implementation ViewController
- (void)someMethod {
[self crashLog:#"error"];
}
#end
Solution B: move crashLog: to a delegate and protocol
#protocol ICloudDBDelegate
-(void)crashLog:(NSString *)message;
#end
#interface DelegateClass : AnyClass <ICloudDBDelegate>
#end
#implementation DelegateClass
-(void)crashLog:(NSString *)message {
NSLog(#"%#", message);
}
#end
#interface ViewController : UIViewController
#end
#implementation ViewController
#property (weak, nonatomic) id <ICloudDBDelegate> iCloudDBDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.iCloudDBDelegate = appDel.iCloudDBDelegate;
}
- (void)someMethod {
[self.iCloudDBDelegate crashLog:#"error"];
}
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate, AppDelProtocolDelegate, iCloudDBDelegate>
#property (strong, nonatomic) id<iCloudDBDelegate>iCloudDBDelegate;
#end
#implementation AppDelegate
- (id<iCloudDBDelegate>)iCloudDBDelegate {
if (!_iCloudDBDelegate) {
_iCloudDBDelegate = [[DelegateClass alloc] init];
}
return _iCloudDBDelegate;
}
#end
Now we have new problem: property iCloudDBDelegate in multiple classes
Solution B + A: move crashLog to a delegate, move iCloudDBDelegate property to a superclass
#protocol ICloudDBDelegate
-(void)crashLog:(NSString *)message;
#end
#interface DelegateClass : AnyClass <ICloudDBDelegate>
#end
#implementation DelegateClass
-(void)crashLog:(NSString *)message {
NSLog(#"%#", message);
}
#end
#interface CommonViewController : UIViewController
#property (weak, nonatomic) id <ICloudDBDelegate> iCloudDBDelegate;
#end
#implementation CommonViewController
#end
#interface ViewController : CommonViewController
#end
#implementation ViewController
- (void)someMethod {
[self.iCloudDBDelegate crashLog:#"error"];
}
#end
Solution C:
Another approach is a singleton object like NSUserDefaults.standardUserDefaults or NSFontManager.sharedFontManager: CloudDBManager.sharedCloudDBManager. No category or protocol required, just include CloudDBManager.h and use CloudDBManager.sharedCloudDBManager from everywhere.
#interface CloudDBManager : NSObject
#property(class, readonly, strong) CloudDBManager *sharedCloudDBManager;
-(void)crashLog:(NSString *)message;
#end
#implementation CloudDBManager
+ (CloudDBManager *)sharedCloudDBManager {
static CloudDBManager *sharedInstance = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
sharedInstance = [[CloudDBManager alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
-(void)crashLog:(NSString *)message {
NSLog(#"%#", message);
}
#end
#interface ViewController : CommonViewController
#end
#implementation ViewController
- (void)someMethod {
[CloudDBManager.sharedCloudDBManager crashLog:#"error"];
}
#end
(I've added this to my own framework, but I don't think thats important)
Yep, that's the typical problem. You've failed to include -ObjC in the link flags.
See Building Objective-C static libraries with categories. This applies to frameworks as well.
ObjC does not create linker symbols for methods. It can't, they're not resolved until runtime. So the category methods aren't seen by the linker as "missing" and it doesn't bother linking the relevant compile unit. This is an important optimization that keeps you from linking all of a massive C library just because you use one function in it, but Objective-C categories break some of the linker's assumptions. The compiler saw the definition (via the header), but the linker didn't care, so there's no error until runtime.
The -ObjC flag says "this C-looking compile unit is actually Objective-C; link all of it even if you don't think you need to."
i have some problems with delegates under xcode while programming an application for Mac OS. I want to communicate with mobile phones if they are in the same network via TCP. I have the following server integrated in my project:
https://github.com/tuscland/osc-echo-example/blob/master/TCPServer.m
https://github.com/tuscland/osc-echo-example/blob/master/TCPServer.h
The only thing I changed at the server is that I extended the start-method so that I can specify a special port. Also I changed the TCPServerDelegation in TCPServer.h to #protocol.
Now I want to set the delegate to this class. But then I get the following error:
[MobileSync copyWithZone:]: unrecognized selector sent to instance 0x109e0f950
I tried a lot but I could not found any solution.
Here is my code, some irrelevant functions are taken out:
MobileSync.h
#import <Foundation/Foundation.h>
#import "TCPServer.h"
#interface MobileSync: NSObject <TCPServerDelegation> {
}
-(id)init;
-(void)StartServer:(int)port;
-(void)StopServer;
// Properties
#end
MobileSync.m
#import "MobileSync.h"
#import "TCPServer.h"
#implementation MobileSync {
TCPServer *tcpServer;
// Other variables
}
-(id)init {
self = [super init];
if (self != nil) {
// Fill variables with values
}
return self;
}
-(void)StartServer:(int)port {
tcpServer = [[TCPServer alloc] init];
[tcpServer setDelegate:self] // <<<<<<< This line is broken
NSError *__autoreleasing* error = NULL;
if ([tcpServer start:port error:error]) {
NSLog(#"Server started successfully");
}
}
-(void)StopServer {
if (tcpServer.stop)
NSLog(#"Server stoped successfully");
}
// different sync functions
// tcpServer Delegate function
-(void)TCPServer:(TCPServer *)server didReceiveConnectionFromAddress:(NSData *)addr inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr {
NSLog(#"Connection received.");
}
TCPServer.h
#import <Foundation/Foundation.h>
#import <CoreServices/CoreServices.h>
NSString * const TCPServerErrorDomain;
typedef enum {
kTCPServerCouldNotBindToIPv4Address = 1,
kTCPServerCouldNotBindToIPv6Address = 2,
kTCPServerNoSocketsAvailable = 3,
} TCPServerErrorCode;
#interface TCPServer : NSObject {
#private
id delegate;
NSString *domain;
NSString *name;
NSString *type;
uint16_t port;
CFSocketRef ipv4socket;
CFsocketRef ipv6socket;
NSNetService *netService;
}
#property (readwrite, copy) id delegate;
#property (readwrite, copy) NSString *domain;
#property (readwrite, copy) NSString *name;
#property (readwrite, copy) NSString *type;
#property (readwrite) uint16_t port;
-(BOOL)start:(int)port error:(NSError **)error;
-(BOOL)stop;
-(void)handleNewConnectionFromAddress:(NSData *)addr inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr;
#end
#protocol TCPServerDelegation
-(void)TCPServer:(TCPServer *)server didReceiveConnectionFromAddress:(NSData *)addr inputStream:(NSInputStream *)istr outputStream:(NSOutputStream *)ostr;
#end
Can someone help me solving the problem? That would be great
I'm having trouble with Objective C.
I'm trying to call a block after I've moved a sprite
The short version of what i'm trying to achieve is that i want to move all of the enemies in an array, and when each one finishes moving i want to check whether it has collided.
The simplified code below shows what i'm trying to do.
My Actor class is defined like this
// -----------------------------
// Actor.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "ScreenObject.h"
typedef void (^actorMoveComplete)(void);
#interface Actor : ScreenObject
{
// actorMoveComplete onMoveComplete;
}
#property (nonatomic) BOOL isMoving;
#property (readwrite, copy) actorMoveComplete onMoveComplete;
#property (nonatomic, retain) CCSprite* sprite;
-(void) moveTo:(CGPoint)targetPosition Speed:(float) speed withCallback:(actorMoveComplete)moveComplete;
#end
// -----------------------------
// Actor.m
#import "Actor.h"
#implementation Actor
#synthesize onMoveComplete;
#synthesize sprite;
-(void) moveTo:(CGPoint)targetPosition Speed:(float) speed withCallback:(actorMoveComplete)moveComplete;
{
onMoveComplete = moveComplete;
id actionMove = [CCMoveTo actionWithDuration:speed position:targetPosition];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[super.sprite runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
-(void) spriteMoveFinished:(id) sender
{
isMoving = NO;
if (onMoveComplete != nil)
onMoveComplete();
}
#end
As you can see i'm trying to store the block in an onMoveComplete parameter (i've also tried it in a private variable), and then call it once the sprite move has completed.
In my calling class i'm iterating through a bunch of actors (enemies) and i want to call this anonymous code block for each actor once the move has completed:
{
[self checkForCollision:enemy];
}
My calling class looks like this.
//------------------------------
//
// GameLayer.h
#import "cocos2d.h"
#import "Actor.h"
#interface GameLayer : CCLayerColor
{
}
#property (nonatomic, copy) NSMutableArray *enemies;
- (void) updateEnemies;
- (void) checkForCollision:(Actor*)actor;
- (BOOL) isMapGridClear:(CGPoint)mapGrid excludeActor:(Actor*)actor;
#end
//------------------------------
// GameLayer.m
#import "GameLayer.h"
#implementation GameLayer
#synthesize enemies;
- (void) updateEnemies
{
for (Actor *enemy in enemies)
{
//
CGPoint newPosition = [self getNewPosition:enemy]; /* method to figure out new position */
[enemy moveDelta:ccp(dX, dY) Speed:enemySpeed withCallback:^{
[self checkForCollision:enemy];
}];
}
}
- (void) checkForCollision:(Actor*)actor
{
if (![self isMapGridClear:actor.gridPosition excludeActor:actor])
{
actor.isCrashed=YES;
[actor loadSprite:self spriteImage:#"crashed.png"];
}
}
- (BOOL) isMapGridClear:(CGPoint)mapGrid excludeActor:(Actor*)actor
{
/* Actual method figures out if there was a collision */
return YES;
}
#end
Unfortunately when I call the onMoveComplete block, i keep getting an EXC_BAD_ACCESS error
Interestingly, if I try to call the block inside the moveTo method, it works (but of course i want this to trigger AFTER the movement has completed).
Can anyone help me with what i'm doing wrong. Am I even using the correct mechanism?
(Apologies for the poorly formatted, incomplete code segments)
You correctly declared your property as copy, but you are setting your instance variable directly to the address of the block without using the generated accessors. That means the block won't get copied and gets destroyed before it is called.
Assign your block using self.onMoveCompleted = moveCompleted and you will be fine.
this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and will then in the end post the error message i get when building.
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue];
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4];
return self;
}
#end
when i build it, i get the following error: EXC_BAD_ACCESS in this line:
#synthesize DATAMODEL;
of DBFactoryClass.m
What #synthesize does is to automatically generate implementations of the accessors for a property. EXC_BAD_ACCESS there means that you're accessing garbage when one of the accessors is executed.
That's probably happening here:
[self setDATAMODEL:[[DBDataModel alloc]init ]];
Make sure that DBDataModel's implementation of init actually returns a legitimate object.
As far as I can tell, your DBFactoryClass class is never stored anywhere, and therefore released right after the allocation if you use ARC (Since you use the strong keyword I assumed you do).
- (BOOL)...didFinishLaunching... {
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
// If you use ARC this might be released right afterwards
return YES;
}
If you want the factory to be a singleton, use something like this
+ (id)sharedInstance {
static dispatch_once_t once;
static MyFoo *instance;
dispatch_once(&once, ^{
instance = [[self alloc] init];
});
return instance;
}