Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSNotificationCenter PasteboardChangedNotification Not Firing

I'm writing a custom keyboard for iOS and I'd like to detect when the user copies some text. I've read that you can use the NSNotificationCenter along with UIPasteboardChangedNotification in order to do this.

However, it seems my selector isn't getting fired when the user copies text. When I put a breakpoint on the addObserver line it appears to get skipped over although breakpoints immediately before and after it are hit. Here is the code I am using:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

    // Register copy notifications 
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleCopy:", name: UIPasteboardChangedNotification, object: nil)
}


func handleCopy(sender: NSNotification) {
//todo: handle the copied text event
}

Can anyone determine what I'm missing?

Edit:

I noticed that the notification fires if I programmatically update the pasteboard after registering the notification, but I still can't figure out why it's not being hit if the user uses the context menu "copy".

like image 342
meverson Avatar asked Nov 11 '14 15:11

meverson


2 Answers

My not a perfect but work enough solution. I already use it in keyboard.

@interface MyPrettyClass : UIViewController

@end

@implementation MyPrettyClass

@property (strong, nonatomic) NSTimer   *pasteboardCheckTimer;
@property (assign, nonatomic) NSUInteger pasteboardchangeCount;

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];

    _pasteboardchangeCount = [[UIPasteboard generalPasteboard] changeCount];


    //Start monitoring the paste board
    _pasteboardCheckTimer = [NSTimer scheduledTimerWithTimeInterval:1
                                                             target:self
                                                           selector:@selector(monitorBoard:)
                                                           userInfo:nil
                                                            repeats:YES];
}

- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];

    [self stopCheckingPasteboard];
}

#pragma mark - Background UIPasteboard periodical check

- (void) stopCheckingPasteboard{

    [_pasteboardCheckTimer invalidate];
    _pasteboardCheckTimer = nil;
}

- (void) monitorBoard:(NSTimer*)timer{

    NSUInteger changeCount = [[UIPasteboard generalPasteboard]; changeCount];
    if (changeCount != _pasteboardchangeCount) { // means pasteboard was changed

        _pasteboardchangeCount = changeCount;
        //Check what is on the paste board
        if ([_pasteboard containsPasteboardTypes:pasteboardTypes()]){

            NSString *newContent = [UIPasteboard generalPasteboard].string;

            _pasteboardContent = newContent;

            [self tryToDoSomethingWithTextContent:newContent];
        }
    }
}

- (void)tryToDoSomethingWithTextContent:(NSString)newContent{
    NSLog(@"Content was changed to: %@",newContent);
}

@end
like image 107
WINSergey Avatar answered Nov 20 '22 20:11

WINSergey


You cannot use NSNotificationCenter since the keyboard extension is a different process.

Cocoa includes two types of notification centers: The NSNotificationCenter class manages notifications within a single process. The NSDistributedNotificationCenter class manages notifications across multiple processes on a single computer.

Try this solution: https://stackoverflow.com/a/28436058/649379 which uses CFNotifications. Don't forget to enable App Groups to get access to the shared container.

More code here: https://github.com/cxa/AppExtensionCommunicator & https://github.com/mutualmobile/MMWormhole

like image 45
SoftDesigner Avatar answered Nov 20 '22 20:11

SoftDesigner