1

I recently added to my app the ability to long-press on a UILabel inside a table cell to make the "Copy" menu appear so the user can copy the text to the pasteboard. It works great both in the simulator and when I build directly to a device. However, when I build & archive (so I can push to TestFlight) the feature does not work.

I attempted the solution in this Stack Overflow question but it didn't work (and doesn't seem relevant since I'm building for iOS 5.0+). I have Optimization Level set to None [-O0] in Build Settings.

  1. How can I debug what's failing if it works fine in Xcode? (IE, is the Gesture Recognizer not working, or the UIMenuController, etc.)
  2. Why is the Archive copy behaving differently than the build-to-device copy?

Here's the relevant code (although I'm 90% sure the issue is not this code but some Xcode setting):

Adding the Gesture Recognizer:

UIGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
                                              initWithTarget:self action:@selector(handleLongPressForCopy:)];
[_postLabel addGestureRecognizer:longPress];            
[self addSubview:_postLabel];

Handle Long Press

- (void)handleLongPressForCopy:(UILongPressGestureRecognizer *)recognizer {
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:            
            NSAssert([self becomeFirstResponder], @"Sorry, UIMenuController will not work with %@ since it cannot become first responder", self);
            UIMenuController *theMenu = [UIMenuController sharedMenuController];
            CGRect displayRect = CGRectMake(_postLabel.frame.origin.x, _postLabel.frame.origin.y, 10, 0);
            [theMenu setTargetRect:displayRect inView:self];
            [theMenu setMenuVisible:YES animated:YES];

            break;
        default:
            break;
    }

}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return (action == @selector(copy:) );
}

As I said, it works great building to the device and in the simulator, just not after Build & Archive.

Community
  • 1
  • 1
Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
  • 3
    Check your scheme. Build & Archive do use Release config and Run use Debug config. So, go to Build Settings and compare Debug & Release configs. Try to change Release settings one by one (to be equal with Debug) and if it fixes your problem, create some sample project and report it to Apple. – zrzka Nov 09 '12 at 18:40
  • 1
    @RobertVojta - thanks! The issue was that the Release build had the `-DNS_BLOCK_ASSERTIONS` flag enabled, which made the release build skip over the line beginning with `NSAssert`. More info here: http://stackoverflow.com/questions/2752574/whats-the-dns-block-assertions-c-compiler-flag - if you want to post a more thorough answer I'm happy to accept it. – Aaron Brager Nov 09 '12 at 19:43
  • 1
    Asserts should have no side-effects; let that be a lesson to you! – tc. Nov 09 '12 at 20:05
  • Aaron, no need to write longer answer for this. But don't remove this setting, assertions should be removed from Release builds. They're useful for debug, etc. but not for release. Move the call outside assertion, put it before, store result to some var and put the var value check in assert. Will work in all cases (w/o asserts). – zrzka Nov 10 '12 at 01:35
  • @RobertVojta Yep, that's what I did. And I really liked tc's advice too. – Aaron Brager Nov 12 '12 at 15:42

1 Answers1

1

The NSAssert method was not called in the release build, because the -DNS_BLOCK_ASSERTIONS flag was enabled for release builds.

In the above code, I fixed the issue by moving [self becomeFirstResponder] to its own line, assigning the return value to a BOOL, and then calling NSAssert on the BOOL.

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287