I know this questions has been posted a lot, but they are all very specific and do not apply to my problem.
[MirrorStarAV startRecording:]: unrecognized selector sent to instance 0x15561d60
I get this error when calling the following method:
- (bool) startRecording {
bool result = NO;
#synchronized(self) {
if (!_recording) { //Exception is raised on this line
result = [self setUpWriter];
startedAt = [[NSDate date] retain];
_recording = YES;
}
}
return result;
}
I call the method as following:
bool _startRecording(){
return [delegateMSA startRecording];
}
[MirrorStarAV startRecording:]: unrecognized selector sent to instance 0x15561d60
The above error message is basically saying that MirrorStarAV doesn't respond to startRecording: so when you call [delegateMSA startRecording]; it is crashing. The delegateMSA has an instance of MirrorStarAV set to it but instances of MirrorStarAV don't respond to `startRecording:
Whilst YES it would be better for you to change your method to something like
bool _startRecording(){
if ([delegateMSA respondsToSelector:#selector(startRecording)])
{
return [delegateMSA startRecording];
}
return false;
}
but this isn't your issue. Note that [MirrorStarAV startRecording:] has a colon : at the end. You are calling startRecording: somewhere over startRecording
Check before, whether the delegate responds to this method, so you can make sure that the object is also able to respond to this selector:
bool _startRecording(){
if ([delegateMSA respondsToSelector:#selector(startRecording)])
{
return [delegateMSA startRecording];
}
return false;
}
Either way, I would recommend to add this selector to the delegates methods with #required:
#protocol MyRecorderDelegate <NSObject>
#required
- (BOOL)startRecording;
#end
So, you would get a compiler warning, if your delegate was not implementing this method.
Verify if the delegateMSA is an instance of class where you have the startRecording method.
Or do something like
bool _startRecording(){
if([delegateMSA respondsToSelector:#selector(startRecording)]) {
return [delegateMSA startRecording];
}
}
Related
I'm trying to debug a mysterious crash I'm seeing in Crashlytics, but haven't been able to reproduce myself.
The error message looks like this:
Fatal Exception: NSInvalidArgumentException
-[NSNull compare:]: unrecognized selector sent to instance 0x1e911bc30
-[NSOrderedSet initWithSet:copyItems:]
Here is the full stacktrack if interested
Because I haven't been able to pinpoint the origin of the crash, I thought I would add a new method to NSNull in order to further debug it via logging.
However I'm not sure how to do it. I think I'd need to add a compare method to NSNull, but I have limited knowledge of objc. I got the idea from this answer. The proposed solution for a similar problem looks like this
BOOL canPerformAction(id withSender) {
return false;
}
- (void)viewDidLoad {
[super viewDidLoad];
Class class = NSClassFromString(#"UIThreadSafeNode");
class_addMethod(class, #selector(canPerformAction:withSender:), (IMP)canPerformAction, "##:");
}
How could I do this in Swift for adding compare to NSNull?
You could add a compare method to NSNull like this:
Objective-C:
#import <objc/runtime.h>
static inline NSComparisonResult compareNulls(id self, SEL _cmd, NSNull *other) {
if([other isKindOfClass:[NSNull class]]) {
return NSOrderedSame; // Nulls are always the same.
}
return NSOrderedDescending;
}
#implementation NSNull (Comparisons)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
const char *encoding = [[NSString stringWithFormat:#"%s#:#", #encode(NSComparisonResult)] UTF8String];
class_addMethod([self class], #selector(compare:), (IMP)compareNulls, encoding);
});
}
#end
Swift:
// Add this code to your AppDelegate.swift file:
import ObjectiveC
fileprivate func compareNulls(_ self: AnyObject, _ _cmd: Selector, _ other: AnyObject) -> ComparisonResult {
if other is NSNull {
return .orderedSame
}
return .orderedDescending
}
fileprivate func addNSNullCompareImplementationIfNecessary() {
let sel = NSSelectorFromString("compareNulls:")
guard class_getMethodImplementation(NSNull.self, sel) == nil else {
return
}
let types = "i#:#"
class_addMethod(NSNull.self, sel, imp_implementationWithBlock(compareNulls), types)
}
// Add this line to your -didFinishLaunching: function:
addNSNullCompareImplementationIfNecessary()
This is only a temporary solution that will stop the crashes.
I would nevertheless encourage you to a) file a bug report, and b) continue investigating why this happened - clearly having an NSNull in this case wasn't expected by Parse...
Let's say I wanted to be able to intercept any method calls to a UIViewController subclass.
First of all, I swizzle the +(instancetype)alloc method and I check if the current instance isKindOfClass:[UIViewController class]. If it is I go ahead and instantiate my proxy with the target.
///swizzled Alloc
+ (instancetype)monitoredAlloc {
id obj = [self monitoredAlloc];
if([obj isKindOfClass:[UIViewController class]]) {
id proxy = [PMGProxy proxyWithObject:obj];
return proxy;
}
return [self monitoredAlloc];
}
---------------------------------------
/// Proxy class
#implementation PMGProxy
+ (instancetype)proxyWithObject:(id)obj {
PMGProxy *proxy = [self alloc];
proxy.obj = obj;
return proxy;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation setTarget:_obj];
[invocation invoke];
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.obj methodSignatureForSelector:sel];
}
- (Class)class {
return [self.obj class];
}
The problem is that I get crashes, so I would expect the implementation of my Proxy is wrong... What am I doing wrong?
Here is the exception:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'This coder requires that replaced objects be returned from initWithCoder:'
From the error it seems that the coder is only happy to accept a different class returned from initCoder: rather than earlier in the process at the alloc stage.
Might be worth looking up NSSecureCoding for more detail on the whole process.
While you’re at it, take a look at the stack track that resulted in your exception, it will give you a bit more perspective on just how deep this rabbit hole goes.
I'm facing the following problem and I already tried a lot. I have also read the others Questions in Stackoverflow like:
Objective-C: Calling selectors with multiple arguments
and the Cocoa Core Competencies about Selectors, but I'm searching for the best way to pass a variable of arguments to a selector.
-(void) runAllStatusDelegates : (SEL)selector
{
for (NSValue *val in self.statusDelegates)
{
id<StatusDelegate> delegate = val;
if ([delegate respondsToSelector:selector])
{
[delegate performSelector:selector];
}
}
}
This method is responsible to call the methods inside the delegates. The parameter is a Selector. My Problem is that the selector can have 0 - 3 arguments, as shown below.
-(void) handleBluetoothEnabled:(BOOL)aEnabled
{
if (aEnabled)
{
[self.statusDelegate bluetoothEnabled];
if (_storedPenSerialNumber != nil && ![_storedSerialNumber isEqual:kUnknownPenID])
{
[self runAllStatusDelegates: #selector(penConnected : _storedSerialNumber : _storedFirmware:)];
}
}
else
{
[self.statusDelegate bluetoothDisabled];
}
}
-(void) handleChooseDevice:(BluetoothDeviceList*)aDevices
{
NSLog(#"Handle Choose Device");
[self runAllStatusDelegates: #selector(chooseDevice:aDevices:)];
}
-(void) handleDiscoveryStarted
{
NSLog(#"Discovery Started");
[self runAllStatusDelegates: #selector(searchingForBluetoothDevice)];
[self.statusDelegate handleStatus:#"Searching for your digipen"];
}
This implementation isn't working because the performSelector is not recognizing the selector.
I also tried to implement it with #selector(penConnected::) withObject:_storedSerialNumber but then I have to implement another method with additional arguments as well and I don't want that.
I'm new to objective-c so I'm not so familiar with all possibilities.
My idea is to pass a String and an Array of arguments to runAllStatusDelegates and build up the selector inside that method, but is this the best way or are there more convenient ways?
I am personally not a fan of NSInvocation for complex signatures. Its really great for enqueueing a simple function call on a queue and running it when you need it but for your case, you know the selector so you don't really need to go the invocation route. I typically find invocations are more useful if you don't actually know the selector you want to call at compile time, maybe its determined by your API etc.
So what I would do is simply pass a block into your runAllStatusDelegates method that will execute against all your delegates:
- (void)performSelector:(SEL)selector againstAllDelegatesWithExecutionBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
for (id<StatusDelegate> delegate in self.statusDelegates)
{
if ([delegate respondsToSelector:selector])
{
blockToExecute(delegate);
}
}
}
Then when you want to call your delegates with a function it looks like this:
[self performSelector:#selector(handleAnswerOfLifeFound)
againstAllDelegatesWithExecutionBlock:^(id<StatusDelegate> delegate){
[delegate handleAnswerOfLifeFound];
}];
I guess the only downside might be that you could change the selector and pass a different function into the block. How I would solve this is by actually making sure not all methods are optional, or if they are optional to make the actual check inside the block, this would clean up the signature:
- (void)callAllDelegatesWithBlock:(void (^)(id<StatusDelegate>))blockToExecute
{
for (id<StatusDelegate> delegate in self.statusDelegates)
{
blockToExecute(delegate);
}
}
and then your actual usage for an optional method:
[self callAllDelegatesWithBlock^(id<StatusDelegate> delegate){
if([delegate respondsToSelector:#selector(handleAnswerOfLifeFound)]){
[delegate handleAnswerOfLifeFound];
}
}];
Still error-prone but at least a bit tidier.
You can use NSInvocation for this case
SEL theSelector = #selector(yourSelector:);
NSMethodSignature *aSignature = [NSMethodSignature instanceMethodSignatureForSelector:theSelector];
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:theSelector];
[anInvocation setTarget:self];
[anInvocation setArgument:&arg1 atIndex:2];
[anInvocation setArgument:&arg2 atIndex:3];
[anInvocation setArgument:&arg3 atIndex:4];
[anInvocation setArgument:&arg4 atIndex:5];
//Add more
Note that the arguments at index 0 and 1 are reserved for target and selector.
For more info http://www.cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
you can binding the arguments to the selector
NSDictionary *argInfo=#{#"arg1":arg1,#"arg2":arg2,...};
objc_setAssociatedObject(self,#selector(chooseDevice:aDevices:),argInfo,OBJC_ASSOCIATION_COPY)
[self runAllStatusDelegates: #selector(chooseDevice:aDevices:)];
then in the
-(void) runAllStatusDelegates : (SEL)selector
{
for (NSValue *val in self.statusDelegates)
{
id<StatusDelegate> delegate = val;
if ([delegate respondsToSelector:selector])
{
NSDictionary *argInfo=objc_getAssociatedObject(self, selector);
//call the fun use arginfo
}
}
}
In the case of method over riding in objective c how selector knows that which method needs to call via selector?
As we dont pass any arguments in slector section...
Ex:
in tmp.m file
There is 2 methods with different arguments
-(void)details
{
}
-(void)details:(NSDictionary *)result
{
}
And when m call another method with the use of selector as:
[mc detailstrac:[[NSUserDefaults standardUserDefaults] valueForKey:#"userID"] tracid:self.trac_id selector:#selector(details:)];
How selector knows to call which method !
I have checked that
-(void)details:(NSDictionary *)result
{
}
this method is called every time then what about
-(void)details
{
}
this ?
Selector will know on the basis how you call the method like from your example,
[mc detailstrac:[[NSUserDefaults standardUserDefaults] valueForKey:#"userID"] tracid:self.trac_id selector:#selector(details:)];
when you call #selector(details:) then the selector will call this method
-(void)details:(NSDictionary *)result { }
And When you call #selector(details) then the selector will call
-(void)details { }
The main difference here is #selector(details) and #selector(details:).
Hope you understand my point!
Happy Coding!
I have followed the tutorial on http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-1/ and managed to get everything work.. The thing is when I submit a score, the keeps saying "Missing Method". How can I fix this problem? Thanks..
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(#"Missed Method");
}
}
PS: code
What is the selector and what is the delegate?
If "Missed Method" is printed, it means that the method the selector is describing, is not implemented on the delegate object.
Maybe you are passing an incorrect selector or maybe the delegate object is not set or not implemented entirely?
Edit based on comments below:
It appears you did not implement the optional methods of the GameCenterManagerDelegate protocol on your MainViewControllerClass, while it is set as the delegate of your GameCenterManager. This is ok, but if you want to get rid of the "Missing method" log message, you should make sure your MainViewControllerClass implements the entire protocol:
#protocol GameCenterManagerDelegate <NSObject>
#optional
- (void) processGameCenterAuth: (NSError*) error;
- (void) scoreReported: (NSError*) error;
- (void) reloadScoresComplete: (GKLeaderboard*) leaderBoard error: (NSError*) error;
- (void) achievementSubmitted: (GKAchievement*) ach error:(NSError*) error;
- (void) achievementResetResult: (NSError*) error;
- (void) mappedPlayerIDToPlayer: (GKPlayer*) player error: (NSError*) error;
#end
For the case you are describing, it is the "- (void) scoreReported: (NSError*) error;" that is missing. The GameCenterManager submits all the scores and once it has done so, it tries to call the scoreReported callback on its delegate. It then notices the method is not present on its delegate and prints out "Missing Method".
If you do not want to do anything once a score has been reported, you can just leave this as is though.