I'm trying to implement Sinch with the iOS SDK and despite following the documentation and tutorials carefully I keep getting this error:
2015-08-01 12:29:22.804 neighborfix[55154:2577760] mainUser username - [e-mail username redacted]
2015-08-01 12:29:22.815 neighborfix[55154:2577760] -[UIDevice reb_platform]: unrecognized selector sent to instance 0x7fc113f1ed40
2015-08-01 12:29:22.827 neighborfix[55154:2577760] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIDevice reb_platform]: unrecognized selector sent to instance 0x7fc113f1ed40'
*** First throw call stack:
(
0 CoreFoundation 0x000000010a5cac65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010a263bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010a5d20ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010a52813c ___forwarding___ + 988
4 CoreFoundation 0x000000010a527cd8 _CF_forwarding_prep_0 + 120
5 neighborfix 0x000000010824fa69 SINUILocalNotificationWithSinchNotification + 13102
6 neighborfix 0x0000000108234817 _ZN6rebrtc13OfflineInvite6encodeERKS0_PhmPm + 4432013
7 neighborfix 0x000000010822f440 _ZN6rebrtc13OfflineInvite6encodeERKS0_PhmPm + 4410550
8 neighborfix 0x0000000108241c79 SINCallOrderByStartTimeComparator + 43762
9 neighborfix 0x00000001082418a0 SINCallOrderByStartTimeComparator + 42777
10 neighborfix 0x0000000107d6ef24 -[AppDelegate sinchClientWithUserId:] + 116
11 neighborfix 0x0000000107d7c31e -[MessagingViewController viewDidLoad] + 574
12 UIKit 0x000000010abbe210 -[UIViewController loadViewIfRequired] + 738
13 UIKit 0x000000010abbe40e -[UIViewController view] + 27
14 UIKit 0x000000010b14b48d -[_UIFullscreenPresentationController _setPresentedViewController:] + 65
15 UIKit 0x000000010ab98da9 -[UIPresentationController initWithPresentedViewController:presentingViewController:] + 105
16 UIKit 0x000000010abca288 -[UIViewController _presentViewController:withAnimationController:completion:] + 1761
17 UIKit 0x000000010abcc701 __62-[UIViewController presentViewController:animated:completion:]_block_invoke + 132
18 UIKit 0x000000010abcc625 -[UIViewController presentViewController:animated:completion:] + 229
19 neighborfix 0x0000000107da73e6 -[FixerRequestController submitPressed:] + 230
20 UIKit 0x000000010aa8eda2 -[UIApplication sendAction:to:from:forEvent:] + 75
21 UIKit 0x000000010aa8eda2 -[UIApplication sendAction:to:from:forEvent:] + 75
22 UIKit 0x000000010aba054a -[UIControl _sendActionsForEvents:withEvent:] + 467
23 UIKit 0x000000010ab9f919 -[UIControl touchesEnded:withEvent:] + 522
24 UIKit 0x000000010aadb998 -[UIWindow _sendTouchesForEvent:] + 735
25 UIKit 0x000000010aadc2c2 -[UIWindow sendEvent:] + 682
26 UIKit 0x000000010aaa2581 -[UIApplication sendEvent:] + 246
27 UIKit 0x000000010aaafd1c _UIApplicationHandleEventFromQueueEvent + 18265
28 UIKit 0x000000010aa8a5dc _UIApplicationHandleEventQueue + 2066
29 CoreFoundation 0x000000010a4fe431 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
30 CoreFoundation 0x000000010a4f42fd __CFRunLoopDoSources0 + 269
31 CoreFoundation 0x000000010a4f3934 __CFRunLoopRun + 868
32 CoreFoundation 0x000000010a4f3366 CFRunLoopRunSpecific + 470
33 GraphicsServices 0x000000010bea4a3e GSEventRunModal + 161
34 UIKit 0x000000010aa8d900 UIApplicationMain + 1282
35 neighborfix 0x0000000107d7d6df main + 111
36 libdyld.dylib 0x000000010f456145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I've tried the following:
Removed Sinch framework and re-installed latest version (3.5.2). I made sure after removing that I deleted from the file directory and all references in "Linked Frameworks and Libraries" in General and "Link Binary With Libraries" in Build Phases had no reference to Sinch before re-installing and making sure it was copied. I have all required frameworks loaded [including those for Parse conflicts] (AVFoundation, Security, Audiotoolbox, Bolts, libstc++6.0.9.dylib) and all required linker flags (-ObjC,-Xlinker,-lc++).
Double-checked proper Sinch delegate implementation (SINClientDelegate,SINMessageClientDelegate) and moved entire Sinch delegate setup/implementation to AppDelegate to make it more straightforward to analyze.
Tried running on actual device as well as simulator
Changed Sinch app setup so that my app does not require JS authentication (even though I do not think this affects iOS SDK).
Searched entire project for any reference to reb_platform and found none. This is probably a call made by a Sinch private method in its library.
Here's my relevant code:
AppDelegate.h:
#import <UIKit/UIKit.h>
#import <Sinch/Sinch.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, SINClientDelegate, SINMessageClientDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) id<SINClient> client;
@property (strong, nonatomic) id<SINMessageClient>sinchMessageClient;
- (void)sinchClientWithUserId:(NSString *)userId;
-(void)sendMessage:(NSString *)messageText toRecipient:(NSString *)recipientId;
@end
AppDelegate.m:
#import "AppDelegate.h"
#import <Parse/Parse.h>
#import <ParseUI/ParseUI.h>
#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>
#import "Config.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[Parse enableLocalDatastore];
// Initialize Parse
[Parse setApplicationId:[APPID]
clientKey:[CLIENT-KEY]];
// rack statistics around application opens.
[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
[PFImageView class];
[[UIBarButtonItem appearanceWhenContainedIn: [UISearchBar class], nil] setTintColor:[UIColor whiteColor]];
//[Fabric with:@[CrashlyticsKit]];
return YES;
}
#pragma mark - Sinch
- (void)sinchClientWithUserId:(NSString *)userId
{
self.client = [Sinch clientWithApplicationKey: [SINCHAPPKEY]
applicationSecret:[SINCHAPPSECRET]
environmentHost:@"sandbox.sinch.com"
userId:userId];
self.client.delegate = self;
[self.client setSupportCalling:NO];
[self.client setSupportMessaging:YES];
[self.client start];
[self.client startListeningOnActiveConnection];
}
- (void)clientDidStart:(id<SINClient>)client
{
NSLog(@"Sinch client started successfully (version: %@)", [Sinch version]);
self.sinchMessageClient = [self.client messageClient];
self.sinchMessageClient.delegate = self;
}
- (void)clientDidFail:(id<SINClient>)client error:(NSError *)error
{
NSLog(@"Sinch client error: %@", [error localizedDescription]);
}
- (void)client:(id<SINClient>)client logMessage:(NSString *)message area:(NSString *)area severity:(SINLogSeverity)severity timestamp:(NSDate *)timestamp
{
if (severity == SINLogSeverityCritical)
{
NSLog(@"%@", message);
}
}
#pragma mark SINMessageClientDelegate methods
// Receiving an incoming message.
- (void)messageClient:(id<SINMessageClient>)messageClient didReceiveIncomingMessage:(id<SINMessage>)message {
[[NSNotificationCenter defaultCenter] postNotificationName:SINCH_MESSAGE_RECEIVED object:self userInfo:@{@"message" : message}];
}
// Finish sending a message
- (void)messageSent:(id<SINMessage>)message recipientId:(NSString *)recipientId {
[[NSNotificationCenter defaultCenter] postNotificationName:SINCH_MESSAGE_SENT object:self userInfo:@{@"message" : message}];
}
// Failed to send a message
- (void)messageFailed:(id<SINMessage>)message info:(id<SINMessageFailureInfo>)messageFailureInfo {
[[NSNotificationCenter defaultCenter] postNotificationName:SINCH_MESSAGE_FAILED object:self userInfo:@{@"message" : message}];
NSLog(@"MessageBoard: message to %@ failed. Description: %@. Reason: %@.", messageFailureInfo.recipientId, messageFailureInfo.error.localizedDescription, messageFailureInfo.error.localizedFailureReason);
}
-(void)messageDelivered:(id<SINMessageDeliveryInfo>)info
{
[[NSNotificationCenter defaultCenter] postNotificationName:SINCH_MESSAGE_SENT object:info];
}
-(void)sendMessage:(NSString *)messageText toRecipient:(NSString *)recipientId{
SINOutgoingMessage *message = [SINOutgoingMessage messageWithRecipient:recipientId text:messageText];
[[self.client messageClient]sendMessage:message];
}
@end
MessagingViewController.h:
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import <Sinch/Sinch.h>
@interface MessagingViewController : UIViewController
@property (strong, nonatomic) PFUser *selectedUser;
@end
MessagingViewController.m:
#import "MessagingViewController.h"
#import "UsersTableViewCell.h"
#import "RecipientTableViewCell.h"
#import "TextInsetLabel.h"
#import <Sinch/Sinch.h>
#import "AppDelegate.h"
#import "Config.h"
typedef NS_ENUM(int, MessageDirection)
{
Incoming,
Outgoing
};
@interface MessagingViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
@property (strong, nonatomic) NSMutableArray *messages;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *messageTextField;
@property (weak, nonatomic) IBOutlet UIButton *btnSendMessage;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *messagingBottomConstraint;
@end
static NSString * CELL_ID_RECIPIENT = @"RecipientCell";
static NSString * CELL_ID_USER = @"UserCell";
@implementation MessagingViewController{
AppDelegate *delegate;
}
#pragma mark - View Lifecycle
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(messageDelivered:) name:SINCH_MESSAGE_RECEIVED object:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//NSLog(@"selectedUser in Messaging - %@",self.selectedUser);
//Init our array to hold chat messages
self.messages = [NSMutableArray new];
//Tableview Setup
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 66.0f;
//Textfield Setup
[self textFieldSetup];
//Setup Sinch message client
PFUser *mainUser = [PFUser currentUser];
NSLog(@"mainUser username - %@",mainUser[@"username"]);
delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate sinchClientWithUserId:mainUser[@"username"]];
}
#pragma mark - Textfield Delegate & Helpers
- (void)textFieldSetup
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
UITapGestureRecognizer *tap;
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
- (void)keyboardWillShow:(NSNotification *)note
{
CGRect keyboardFrameEnd = [[[note userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
self.messagingBottomConstraint.constant = keyboardFrameEnd.size.height - 24;//Was 48
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
}];
[self scrollToBottom];
}
- (void)keyboardWillBeHidden:(NSNotification *)note
{
self.messagingBottomConstraint.constant = 0;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)dismissKeyboard
{
[self.messageTextField resignFirstResponder];
[self scrollToBottom];
}
- (void)scrollToBottom
{
//Scroll to bottom
if (self.messages.count > 0)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
#pragma mark - Table View Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return self.messages.count;
NSLog(@"self.messages array - %@",self.messages);
return [self.messages count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [UITableViewCell new];
id<SINMessage> message = [self.messages[indexPath.row] firstObject];
MessageDirection direction = (MessageDirection)[[self.messages[indexPath.row] lastObject] intValue];
if (direction == Incoming)
{
cell = [self.tableView dequeueReusableCellWithIdentifier:CELL_ID_RECIPIENT];
((RecipientTableViewCell *)cell).message.text = message.text;
}
else
{
cell = [self.tableView dequeueReusableCellWithIdentifier:CELL_ID_USER];
((UsersTableViewCell *)cell).message.text = message.text;
}
return cell;
}
#pragma mark - Sending Message
- (IBAction)sendMessage:(id)sender
{
[self dismissKeyboard];
NSLog(@"username of recipient - %@",self.selectedUser[@"username"]);
NSString *outgoingMessage = self.messageTextField.text;
[delegate sendMessage:outgoingMessage toRecipient:self.selectedUser[@"username"]];
}
- (void)messageDelivered:(NSNotification *)notification
{
NSString *chatMessage = [[notification userInfo] objectForKey:@"message"];
[self.messages addObject:chatMessage];
[self.tableView reloadData];
[self scrollToBottom];
}
@end
The error is invoked by this line in MessagingViewController.m apparently:
[delegate sinchClientWithUserId:mainUser[@"username"]];
Which is calling this method in AppDelegate:
- (void)sinchClientWithUserId:(NSString *)userId
{
self.client = [Sinch clientWithApplicationKey: [SINCHAPPKEY]
applicationSecret:[SINCHAPPSECRET]
environmentHost:@"sandbox.sinch.com"
userId:userId];
self.client.delegate = self;
[self.client setSupportCalling:NO];
[self.client setSupportMessaging:YES];
[self.client start];
[self.client startListeningOnActiveConnection];
}
A few points in case they are relevant:
Xcode 6.3.2, iOS 7.0+
Using Parse and using the stored e-mail username for users as the username for Sinch
Using Crashlytics/Fabric
I show no users created on Sinch dashboard.
Any help is appreciated. Sinch looks like a really powerful tool but I can't seem to get it going. Thanks.
I finally got past this problem by removing the Parse FB utilities and using the -all_load linker flag. The Sinch client now starts and the error no longer appears. I'm not sure what happened to cause the error but appears to be some conflict with Sinch and Parse FB Utils. I had already followed Sinch instructions on loading extra libs and frameworks to resolve any such conflict but apparently that was not enough.