13

I've been struggling with this issue for a while now and I just can't seem to reproduce it accurately enough to describe the exact use-case. Essentially, what I'm doing is issuing a request for opening a native iOS 6.0 Facebook share dialog (using the Facebook iOS SDK 3.1.1):

if ([[SocialManager sharedManager] isNativeFacebookShareDialogAvailable]) {

        if (!url) {
            url = [NSURL URLWithString:@""];
        }

        if (!imageUrl) {
            imageUrl = [NSURL URLWithString:@""];
        }

        dispatch_async(backgroundQueue, ^{

            NSData *imageData  = [NSData dataWithContentsOfURL:imageUrl];
            UIImage *image     = [UIImage imageWithData:imageData];

            if (!image) {
                image = [[UIImage alloc] init];
            }

            if ([FBNativeDialogs canPresentShareDialogWithSession:[FBSession activeSession]]) {

                dispatch_async(dispatch_get_main_queue(), ^{
                    [FBNativeDialogs presentShareDialogModallyFrom:sender initialText:initialText images:@[image] urls:@[url] handler:^(FBNativeDialogResult result, NSError *error) {
                        if (error) {
                            failBlock([[error userInfo] description]);
                        } else {
                            if (result == FBNativeDialogResultSucceeded) {
                                completionBlock();
                            } else if (result == FBNativeDialogResultCancelled) {
                                failBlock(@"User cancelled");
                            } else if (result == FBNativeDialogResultError) {
                                failBlock(@"Unknown error");
                            }
                        }
                    }];
                });

            } else {
                LogErr(@"Can't display native share dialog for active session");
            }
        });
    }

Right after presentShareDialogModallyFrom:sender is called, I either get the following crash log:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x1d161490> was mutated while being enumerated.'
*** First throw call stack:
(0x32ede2a3 0x326b097f 0x32eddd85 0x35da094d 0x32edb62f 0x35da07f5 0x35e7e5e5 0x35e0ccd7 0x35e0cb6d 0x372c490f 0x35e0ca61 0x35e160d5 0x372b783b 0x35e160b1 0x372b711f 0x372b699b 0x372b6895 0x372c5215 0x372c53b9 0x36f5fa11 0x36f5f8a4)
libc++abi.dylib: terminate called throwing an exception

OR I get no crash and the native share dialog appears as it should.

The stack implies a call on a thread called UIRemoteViewControllerCreationRequest at this point, here are 2 examples for two different crashes: enter image description here enter image description here

Thanks for your help

Stavash
  • 14,244
  • 5
  • 52
  • 80
  • where is your snippet being called from (e.g., viewDidLoad or some IBAction)? – Chris Pan Feb 15 '13 at 17:14
  • An IBAction calls this instance method, which is declared as part of a "SocialManager" singleton. – Stavash Feb 16 '13 at 08:37
  • I have the same problem with FB SDK. I have just inspected the SDK source but I have found nothing that could cause it. Have you ever found the reason? – Sulthan Jun 22 '13 at 18:29
  • No, though the latest SDK doesn't cause this mess for me – Stavash Jun 23 '13 at 07:16
  • @Stavash I guess I have finally found my problem. I don't think it was ever a problem with the SDK. The social framework just does things that I didn't expect - see my answer. – Sulthan Jun 24 '13 at 09:37
  • Very interesting scenario. I'll look into it on my end and see if this is a similar issue. – Stavash Jun 25 '13 at 04:51

7 Answers7

2

After a lot of experimenting with my application and looking into Facebook SDK source I realized 3 things:

  1. Creating a SLComposeViewController by yourself doesn't help. Facebook SDK is pretty simple in this, it just creates the controller exactly like the code in the answer with bonus.

  2. When you are authorizing the FB session, your application is deactivated once or more times. This is caused by the permission confirmation alerts appearing.

  3. The UIRemoteViewController is actually the SLComposeViewController which is run in a different process.

What caused my error?

  1. User confirms FB permissions
  2. This triggers applicationDidBecomeActive:
  3. It also triggers FB callback to present the dialog.
  4. My applicationDidBecomeActive: was doing something with the UI what was not supposed to be done when the FB dialogs were appearing (tirggering a table reload).

Also, there is another thing to be careful of - the handler of presentShareDialogModallyFrom... is not called on any particular thread (see SLComposeViewController docs). That means that you should use dispatch_async(dispatch_get_main_queue(), ...) from the handler if you are updating UI from it.

EDIT: Obviously, the previous steps fixed some crashes but one of the crashes was not solved. After a lot of googling and searching Apple Developer forums, I think there is a bug in iOS 6 connected with Remote Controllers and using UIAppearance, especially the appearance of UINavigationBar. I am currently removing the use of UIApperance from my app.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
1

This is a very strange way to post a post to Facebook. Here is a much simpler way that never crashes.

ViewController.h

#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import <Accounts/Accounts.h>

@interface ViewController : UIViewController {
SLComposeViewController *mySLComposerSheet;
}
- (IBAction)PostToFacebook:(id)sender;

@end

ViewController.m @implementation ViewController

- (IBAction)PostToFacebook:(id)sender {
mySLComposerSheet = [[SLComposeViewController alloc] init];
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[mySLComposerSheet setInitialText:@"Place Text Here"];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
@end

If needed, there is a video here.

OnkaPlonka
  • 1,232
  • 10
  • 19
  • 1
    I don't understand why you consider this a strange way to post to Facebook. The way I see it, Facebook created an SDK just for the purpose of working with iOS so it would be pretty vain to attempt a better implementation using the Social framework as an individual developer. That said, I want to thank you for your answer but I wish to use the SDK implementation. – Stavash Feb 17 '13 at 20:44
  • Working with SLComposeViewController was the only workaround that helped, so I'm giving you the bounty. There is however a problem in your code - a redundant alloc,init. Thank you for your answer – Stavash Feb 21 '13 at 10:14
1

Sorry some of this is rather guessing, but I thought I would try:

Are you sure that canPresentShareDialogWithSession is safe to call from a non-UI thread?

You have a line in both stacks of _NSDictionaryEnumerate. It looks like from higher functions, that something is calling enumerateKeysAndObjectsUsingBlock:.

Based on your note of things crashing just after [presentShareDialogModallyFrom:sender]. Is there something being released when sender's view disappears?

Variable "image" is either retained or autoreleased depending on which code path it took.

Walt Sellers
  • 3,806
  • 30
  • 35
  • I thought about the "canPresentShareDialogWithSession" thing, tried calling it from the main thread and got the exact same result. Like I told DrAL3X - it's not me doing the call on a non-UI thread, it's internal Facebook SDK operations. – Stavash Feb 19 '13 at 09:29
1

I think the problem is what Walt already said. In your code, something is done outside the main thread.

In the crash log you can see that someone is setting the appearance (UIAppearance) on some UI element from a non-UI thread. That's the problem. This operation MUST be done ONLY in the UI (main) thread.

DrAL3X
  • 769
  • 8
  • 18
  • I agree. The thing is - it's not me doing the call, it's internal Facebook SDK operations. "presentShareDialogModallyFrom" is being called from the main thread as you can see. – Stavash Feb 19 '13 at 09:28
  • Facebook SDK is open source, you can see exactly what it does. Go deep inside and try to understand where the problem stats. – DrAL3X Feb 20 '13 at 14:10
1

I believe this has to do with the combination of the UIAppearance methods and launching a UIRemoteViewController from a background thread. We're having the same issue in our app. I'm going to change our presenter class to present all our remote viewControllers from the main thread and see if that helps.

In your case, I guess something in the Facebook SDK is presenting something from a background thread.

I'll update after I've verified that my fix works.

Mark
  • 7,167
  • 4
  • 44
  • 68
1

This is a bug in iOS 6 and Social Framework, check answer here UINavigationBar appearance and Facebook-Sheet Bug

How to solve this?

Simply instead of using [UINavigationBar appearance] use [UINavigationBar appearanceWhenContainedIn:...]

You can use custom class for your navigation controller (eg. CustomNavigationController) and then apply it in appearance:

[UINavigationBar appearanceWhenContainedIn:[CustomNavigationController class], nil]

From my experiments it should be used on all appearance methods, not only UINavigationBar but also UIBarButtonItem etc. (on every object you send appearance message to)

Community
  • 1
  • 1
Konrad Szczęśniak
  • 1,960
  • 1
  • 14
  • 13
-2

I think you know what is obvious but I met this error once and it was an NSMutableArray that was mutated while being enumerated inside a for..in statement.

Look at the NSMutableArray, you'll find your error.

Byt the way, if you target ios6, why don't you use the social framework with native facebook implementation ?

Diwann
  • 888
  • 1
  • 8
  • 28
  • This has nothing to do with iterating over arrays, the array that's causing the crash is managed by the OS and probably represents view hierarchy in this context. I'm using the Facebook SDK to provide 5.0+ compatibility. – Stavash Feb 16 '13 at 08:36
  • Or perhaps it does, but crashes outside the posted code ? It's not because this code causes the crash that the crash happens inside this code. – Diwann Feb 16 '13 at 10:13
  • Of course, but the code that causes the crash is unavailable to me because it has something to do with the SDK (which is not open source) – Stavash Feb 16 '13 at 11:23