1

I have a problem with SLComposeViewController in IOS 8. I want to show Facebook sharing window and after it's done - show Twitter sharing window. That's why I need to use completion blocks and to avoid retain cycles I have to use __weak SLComposeViewController, but when I call

[viewController presentViewController:facebookSLController animated:YES completion:Nil];

my facebookSLController is nil. It's because of __weak. But why it didn't crash in IOS 7? And how can I solve this problem? Here is part of code:

if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {

    __weak SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];

    [controller setInitialText:text];

    //When facebook sharing end - we start twitter sharing
    [controller setCompletionHandler:^(SLComposeViewControllerResult result) {
        [controller dismissViewControllerAnimated:YES completion:nil];
        [self shareTwitterImage:image withText:strGetApp fromViewController:viewController];
    }];


    [controller addImage:image];

    [viewController presentViewController:controller animated:YES completion:Nil];

}

1 Answers1

2

The problem is that you are messing with memory management without knowing what you're doing. Your code makes no sense. Declaring a variable weak and assigning a newly created instance to that variable means that that instance will go out of existence immediately - because there is nothing to retain it. Normally, the strong reference of the variable is what would retain it, but by declaring the variable weak you have prevented that. Thus you may expect controller to vanish in a puff smoke the instant you declare it - and that is what it's doing. This code never worked correctly, in iOS 7 or in iOS 8.

If you want to pass the view controller referred to thru controller thru a weak reference into the block, then do that; take another reference, a weak reference, to controller and let it pass into the block (and do the "weak-strong dance" with it so that your block behaves correctly). But controller itself needs to be a normal reference. Thus (warning, typed directly without testing, beware of typos):

SLComposeViewController *controller = 
    [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[controller setInitialText:text];
// take a weak ref to pass into the block
__weak SLComposeViewController *weakController = controller;
[controller setCompletionHandler:^(SLComposeViewControllerResult result) {
    // and now do the weak-strong dance with weakController...
    // and do NOT refer to controller inside the block
    SLComposeViewController *strongController = weakController;
    if (strongController != nil) {
        // ... your code here; refer only to strongController
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • And for the canonical weak-strong dance, see my book: http://www.apeth.com/iOSBook/ch12.html#EXstrongWeakDance – matt Jan 08 '15 at 00:41