so created a simple application to test out sendbird services, they look best, so i have read their documentation, and at this moment. i made something.. and i got a problem there, when do i have to call the didReceiveMessage or why mine is not working?
myCode
- (IBAction)connnect:(id)sender {
[SBDOpenChannel getChannelWithUrl:#"iDict" completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
if (error != nil) {
NSLog(#"Error 1 : %#", error.localizedDescription);
return;
}
[channel enterChannelWithCompletionHandler:^(SBDError * _Nullable error) {
if (error != nil) {
NSLog(#"Error: %#", error);
return;
}
NSLog(#"Connected to Channel : %#",channel.channelUrl);
// ...
}];
}];
}
- (IBAction)sendMessage:(id)sender {
[self.channel sendUserMessage:#"pop" data:#"Hey" completionHandler:^(SBDUserMessage * _Nullable userMessage, SBDError * _Nullable error) {
if (error != nil) {
NSLog(#"Error: %#", error);
return;
}
}];
}
- (void)channel:(SBDBaseChannel * _Nonnull)sender didReceiveMessage:(SBDBaseMessage * _Nonnull)message {
if (sender == self.channel) {
NSLog(#"From Button.Message Received From %# message is : %# in channel :",sender.description,message.description);
} else {
NSLog(#"Failed");
}
}
#end
Did you register your current class as the channel's delegate? You need to do this so that when the channel receives a message, it will call your delegate with the received message.
So in your class, I am assuming it's a UIViewController, declare it to conform to like so:
#interface OpenChannelViewController : ViewController<SBDChannelDelegate>
#end
Somewhere in your viewDidLoad, you should add this class to the channel delegate.
- (void)viewDidLoad {
[SBDMain addChannelDelegate:self identifier:UNIQUE_HANDLER_ID];
}
Now you should receive messages. Info was taken from here:
https://docs.sendbird.com/ios?_ga=1.152151677.594130729.1491427400#open_channel_3_receiving_messages
Good luck!
Related
I'm trying to create a DownloadOperation subclass of NSOperation to download data asynchronously. Everything seemed to be working fine until I tried to add cancelling support. Basically, the completion handler of the operation's NSURLSessionDownloadTask seems to be called after the operation has been released. It will crash with EXC_BAD_ACCESS at the line weakSelf.state = kFinished.
The full sample project is here: https://github.com/angstsmurf/DownloadOperationQueue. Press Command+. after running to crash.
#import "DownloadOperation.h"
typedef enum OperationState : NSUInteger {
kReady,
kExecuting,
kFinished
} OperationState;
#interface DownloadOperation ()
#property NSURLSessionDownloadTask *task;
#property OperationState state;
#end
#implementation DownloadOperation
// default state is ready (when the operation is created)
#synthesize state = _state;
- (void)setState:(OperationState)state {
#synchronized(self) {
if (_state != state) {
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_state = state;
[self didChangeValueForKey: #"isExecuting"];
[self didChangeValueForKey: #"isFinished"];
}
}
}
- (OperationState)state {
#synchronized (self) {
return _state;
}
}
- (BOOL)isReady { return (self.state == kReady); }
- (BOOL)isExecuting { return (self.state == kExecuting); }
- (BOOL)isFinished { return (self.state == kFinished); }
- (BOOL)isAsynchronous {
return YES;
}
- (instancetype)initWithSession:(NSURLSession *)session downloadTaskURL:(NSURL *)downloadTaskURL completionHandler:(nullable void (^)(NSURL * _Nullable, NSURLResponse * _Nullable, NSError * _Nullable))completionHandler {
self = [super init];
if (self) {
__unsafe_unretained DownloadOperation *weakSelf = self;
// use weak self to prevent retain cycle
_task = [[NSURLSession sharedSession] downloadTaskWithURL:downloadTaskURL
completionHandler:^(NSURL * _Nullable localURL, NSURLResponse * _Nullable response, NSError * _Nullable error) {
/*
if there is a custom completionHandler defined,
pass the result gotten in downloadTask's completionHandler to the
custom completionHandler
*/
if (completionHandler) {
completionHandler(localURL, response, error);
}
/*
set the operation state to finished once
the download task is completed or have error
*/
weakSelf.state = kFinished;
}];
}
return self;
}
- (void)start {
/*
if the operation or queue got cancelled even
before the operation has started, set the
operation state to finished and return
*/
if (self.cancelled) {
self.state = kFinished;
return;
}
// set the state to executing
self.state = kExecuting;
NSLog(#"downloading %#", self.task.originalRequest.URL.absoluteString);
// start the downloading
[self.task resume];
}
-(void)cancel {
[super cancel];
// cancel the downloading
[self.task cancel];
}
#end
As pointed out in the comments by Scott Thompson, the correct keyword to use for the weakSelf variable is __weak, not __unsafe_unretained.
I'm currently developing a React Native plugin for Snapchat's SnapKit SDK.
I can't seem to get the addLoginStatusObserver method to work (detailed here: https://snapkit.com/docs/api/ios/) and I suspect it's my lack of experience with Objective C's protocol/interface/implementation features.
Here's a trimmed down version of the code:
...
#interface RNSnapSDKListener : NSObject<SCSDKLoginStatusObserver> {
...
}
- (void)scsdkLoginLinkDidSucceed;
- (void)scsdkLoginLinkDidFail;
- (void)scsdkLoginDidUnlink;
...
#end
#implementation RNSnapSDKListener
- (void)scsdkLoginLinkDidSucceed{
NSLog(#"[RNSnapSDKListener] Snapchat Did Login!");
}
- (void)scsdkLoginLinkDidFail{
NSLog(#"[RNSnapSDKListener] Snapchat Did Fail!");
}
- (void)scsdkLoginDidUnlink{
NSLog(#"[RNSnapSDKListener] Snapchat Did Unlink!");
}
- (void)setDelegate: (RCTEventEmitter*) eventEmitter{
NSLog(#"[RNSnapSDKListener] Delegate Set!");
}
#end
#implementation RNSnapSDK
...
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(initialize){
RNSnapSDKListener *listener = [[RNSnapSDKListener alloc] init];
[listener setDelegate:self];
[SCSDKLoginClient addLoginStatusObserver:listener];
}
RCT_EXPORT_METHOD(login)
{
[SCSDKLoginClient loginFromViewController:[UIApplication sharedApplication].delegate.window.rootViewController completion:^(BOOL success, NSError * _Nullable error) {
}];
}
RCT_EXPORT_METHOD(logout: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
[SCSDKLoginClient unlinkAllSessionsWithCompletion:^(BOOL success) {
NSLog(#"Logout %s", success ? "true" : "false");
resolve(NULL);
}];
}
RCT_EXPORT_METHOD(getUserData: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
NSString *graphQLQuery = #"{me{externalId, displayName, bitmoji{avatar}}}";
NSDictionary *variables = #{#"page": #"bitmoji"};
[SCSDKLoginClient fetchUserDataWithQuery:graphQLQuery
variables:variables
success:^(NSDictionary *resources) {
NSDictionary *data = resources[#"data"];
resolve(data);
} failure:^(NSError * error, BOOL isUserLoggedOut) {
NSLog(#"%#",[error localizedDescription]);
NSLog(#" %s", isUserLoggedOut ? "true" : "false");
if(isUserLoggedOut){
[SCSDKLoginClient loginFromViewController:[UIApplication sharedApplication].delegate.window.rootViewController completion:^(BOOL success, NSError * _Nullable error) {
}];
}else{
reject(#"error", [error localizedDescription], error);
}
}];
}
NSURL *saved;
RCT_EXPORT_METHOD(authenticateDeepLink: (NSString *)url)
{
NSURL *finalUrl = [NSURL URLWithString:url];
saved = finalUrl;
[SCSDKLoginClient application:[UIApplication sharedApplication] openURL:finalUrl options:[NSMutableDictionary dictionary]];
}
...
#end
.initialize() is called inside the React Native module, and the setDelegate() method is called successfully (printing out "Delegate set" - this is for the react-native event bridge), but the other [RNSnapSDKListener]s dont print when they should (after logging in or logging out)
Is this something I'm doing wrong with objective-c or some other misuse of Snapchat's SDK?
Thanks!
The problem ended up being that the RNSnapSDKListener *listener needed to be declared as a global variable and initialized inside initialize() - not entirely sure why though - something with garbage collection maybe?
I'm pretty new to RubyMotion and I've just hit a wall.
I'm trying to do some LinkedIn oauth work and I need to convert the following to RubyMotion
client = LIALinkedInHttpClient.clientForApplication(application, presentingViewController:nil)
client getAuthorizationCode:^(NSString * code) {
[self.client getAccessToken:code success:^(NSDictionary *accessTokenData) {
NSString *accessToken = [accessTokenData objectForKey:#"access_token"];
[self.client getPath:[NSString stringWithFormat:#"https://api.linkedin.com/v1/people/~?oauth2_access_token=%#&format=json", accessToken] parameters:nil success:^(AFHTTPRequestOperation * operation, NSDictionary *result) {
NSLog(#"current user %#", result);
} failure:^(AFHTTPRequestOperation * operation, NSError *error) {
NSLog(#"failed to fetch current user %#", error);
}];
} failure:^(NSError *error) {
NSLog(#"Quering accessToken failed %#", error);
}];
} cancel:^{
NSLog(#"Authorization was cancelled by user");
} failure:^(NSError *error) {
NSLog(#"Authorization failed %#", error);
}];
Could anyone possibly point me in the write direction?
The less-typing way using Ruby 2.0's stabby lambdas looks like this:
client.getAuthorizationCode -> (code) {
NSLog "Success"
}, cancel: ->
NSLog "Auth was cancelled"
}, failure: -> (error) {
NSLog "Auth failed"
}
Here's an idea of how you'd use Objective-C blocks in RubyMotion:
client.getAuthorizationCode(lambda { |code|
}, cancel: lambda {
}, failure: lambda { |error|
})
I believe you can use the lambda shorthand -> or Proc if you prefer. See the RubyMotion docs for more info. They demonstrate using do and end to begin and finish the block, but for this purpose, I prefer braces.
I have the same problem as in this thread: What causes "Missed Method" in this code?
but i do not understand how to solve this or if it even is a problem.
I am doing the tutorial in the book "Beginning iOS Game Center and Game Kit" and get this problem. I do get "...Missed Method" all the time and is trying to understand why, unfortunately i do not. I also tried to use the answer on the thread above but to no avail.
I would very much appreciate some help on this one.
The code i am using currently:
#import "GameCenterManager.h"
#implementation GameCenterManager
#synthesize delegate;
+(BOOL)isGameCenterAvailable {
Class gcClass = (NSClassFromString(#"GKLocalPlayer"));
NSString *reqSysVer = #"4.1";
NSString *currSysVer = [[UIDevice currentDevice]systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);
}
-(void)retrieveFriendsList {
if ([GKLocalPlayer localPlayer].authenticated == YES) {
[[GKLocalPlayer localPlayer]loadFriendsWithCompletionHandler:^(NSArray *friends, NSError *error) {
[self callDelegateOnMainThread:#selector(friendsFinishLoading:error:) withArg:friends error:error];
}];
} else {
NSLog(#"...You must authenticate first");
}
}
-(void)authenticateLocalUser {
if ([GKLocalPlayer localPlayer].authenticated) {
return;
}
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error){
[self callDelegateOnMainThread:#selector(processGameCenterAuthentication:) withArg:NULL error: error];
}];
}
-(void)callDelegateOnMainThread:(SEL)selector withArg: (id) arg error:(NSError*) err {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self callDelegate:selector withArg: arg error: err];
});
}
-(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");
}
}
Output, after GC authorization:
...Missed Method
You code calls [self callDelegateOnMainThread:#selector(processGameCenterAuthentication:) withArg:NULL error: error]; which ends up in a method (callDelegate:withArg:error:) that checks wether your class implemented the processGameCenterAuthentication: method. You get the Missed Method output because you don't seem to have implemented it.
I'm using the AFNetworking library to pull a JSON feed from a server to populate a UIPickerView, but I'm having a little trouble wrapping my head around the asynchronous way of doing things. The #property classChoices is an NSArray that's being used to populate the UIPickerView, so that the web call is only performed once. However, since the block isn't finished by the time the instance variable is returned, the getter returns nil, and it eventually causes my program to crash later on. Any help in fixing this would be greatly appreciated. Let me know if you need any additional information.
PickerViewController.m classChoices Getter
- (NSArray *)classChoices {
if (!_classChoices) {
// self.brain here refers to code for the SignUpPickerBrain below
[self.brain classChoicesForSignUpWithBlock:^(NSArray *classChoices) {
_classChoices = classChoices;
}];
}
return _classChoices;
}
SignUpPickerBrain.m
- (NSArray *)classChoicesForSignUpWithBlock:(void (^)(NSArray *classChoices))block {
[[UloopAPIClient sharedClient] getPath:#"mobClass.php" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseJSON) {
NSLog(responseJSON);
if (block) {
block(responseJSON);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
if (block) {
block(nil);
}
}];
}
You need a method like the following in your PickerViewController which returns the array once it has been downloaded. Once the callback has been returned, you can then continue on with your code:
- (void)classChoices:(void (^) (NSArray * classChoices)) _callback {
if (!self.classChoices) {
// self.brain here refers to code for the SignUpPickerBrain below
[self.brain classChoicesForSignUpWithBlock:^(NSArray *classChoices) {
_callback(classChoices);
}];
}
}
// call the method
- (void) viewDidLoad {
[super viewDidLoad];
[self classChoices:^(NSArray * updatedChoices) {
self.classChoices = updatedChoices;
[self.pickerView reloadAllComponents];
}];
}