Will NSNotificationCenter call back method be called in main thread or background thread? - mpmovieplayercontroller

My code is just play a downloaded mp4 files and register the view controller to observe the notification of end of player.
It works pretty good in not only iOS5 but also iOS4.
But I just want to know for sure that whether the call back method by NotificationCenter will be called in background thread or main thread.
(loadMoviePlayerStateChanged:(NSNotification*)notification is call back method in my code)
Do anyone know exactly about this?
- (void) playMovie:(NSURL *)fileURL {
MPMoviePlayerViewController *MPVC = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
self.mMPVC = MPVC;
self.mMPVC.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadMoviePlayerStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.mMPVC.moviePlayer];
[MPVC.moviePlayer prepareToPlay];
[MPVC release];
}
- (void) loadMoviePlayerStateChanged:(NSNotification*)notification {
int loadState = self.mMPVC.moviePlayer.loadState;
if(loadState & MPMovieLoadStateUnknown) {
IGLog(#"The load state is not known at this time.");
return;
}
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.mMPVC.moviePlayer];
[self.mMPVC.view setFrame:self.view.bounds];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.mMPVC.moviePlayer];
/* if I do not use performSelectorOnMainThread method to add subview to UIViewController`s view,
the view of MPMoviePlayerViewController would not be removed from superview normally */
[self.view performSelectorOnMainThread:#selector(addSubview:)
withObject:self.mMPVC.view
waitUntilDone:YES];
[self.mMPVC.moviePlayer play];
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
[self.mMPVC.moviePlayer stop];
[self.mMPVC.moviePlayer.view removeFromSuperview];
NSString* dstFilePath = [[_mPopupVC.mSelectedMovie decryptionFilePath] stringByAppendingPathExtension:#"mp4"];
[[NSFileManager defaultManager] removeItemAtPath:dstFilePath error:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.mMPVC.moviePlayer];
}

I got an answer for my question in apple developer site, the answer is,
"notifications safely thread themselves and perform their selectors on the main thread.
however, your problem is that you should not be adding and removing the player view like that, use the presentModalVideo methods provided as a category in your view controller class."
and I solved the problem that i had. code is below..
- (void) playMovie
{
/*
*create and initialize MPMoviePlayerViewController with specified url and retain it
*/
MPMoviePlayerViewController *MPVC = [[MPMoviePlayerViewController alloc] initWithContentURL:vodWebURL];
self.mMPVC = MPVC;
[MPVC release];
self.mMPVC.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
self.mMPVC.moviePlayer.shouldAutoplay = NO;
[self.mMPVC.moviePlayer prepareToPlay];
/*
*register movie player to NSNotificationCenter
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadMoviePlayerStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.mMPVC.moviePlayer];
}
- (void) loadMoviePlayerStateChanged:(NSNotification*)notification
{
/*
*do your work for the state of the movie player
*/
int loadState = self.mMPVC.moviePlayer.loadState;
if(loadState & MPMovieLoadStateUnknown) {
NSLog(#"The load state is not known at this time.");
return;
} else if(loadState & MPMovieLoadStatePlayable) {
NSLog(#"MPMovieLoadStatePlayable : The buffer has enough data that playback can begin, but it may run out of data before playback finishes.");
} else if(loadState & MPMovieLoadStatePlaythroughOK) {
NSLog(#"MPMovieLoadStatePlaythroughOK : Enough data has been buffered for playback to continue uninterrupted.");
} else if(loadState & MPMovieLoadStateStalled) {
NSLog(#"MPMovieLoadStateStalled : The buffering of data has stalled.");
}
/*
*set frame of the view of MPMoviePlayerViewController and add it
*call play method
*/
[self.mMPVC.view setFrame:self.view.superview.bounds];
[self.view.superview addSubview:self.mMPVC.view];
[self.mMPVC.moviePlayer play];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.mMPVC.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.mMPVC.moviePlayer];
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
/*
*remove the view of MPMoviePlayerViewController
*release MPMoviePlayerViewController
*/
[self.mMPVC.moviePlayer stop];
[self.mMPVC.moviePlayer.view removeFromSuperview];
self.mMPVC = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.mMPVC.moviePlayer];
}

Related

Is there a change to the behaviour of UIKeyboardWillShowNotification in iOS 8?

I have had a simple UIView block animation that handles animating a group of text fields into view when the keyboard will show (and animate them back when the keyboard hides). This has worked fine in iOS 6 & 7, but now I'm getting incorrect behavior, and it all points to some change in UIKeyboardWillShowNotification.
I set up an isolated project to test this further on a single text field, with two buttons that call exactly the same methods that are fired for the keyboard's WillShow and WillHide notifications. See the results in this video:
Video example
This seems like a bug to me, or it might be a change to the behavior of this notification. Does anyone know if this is intended and/or what can be done about it?
Here is the relevant code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
self.textField.frame = CGRectOffset(self.textField.frame, 0.f, _destY - _origY);
}];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
self.textField.frame = CGRectOffset(self.textField.frame, 0.f, _origY - _destY);
}];
}

MPMoivePLayerController crash when click full screen button

I use SWRealViewController for my sidebar.
My moviePlayer work fine with out fullscreen, but when i click fullscreen moviePlayer crash and i got an error:
2014-01-01 19:23:00.860 Chingfong[56193:70b] Warning: Attempt to
dismiss from view controller while
a presentation or dismiss is in progress!
Here i my code in movieVC.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface movieVC : UIViewController
{
NSString *link;
}
#property(nonatomic,retain) NSString *link;
#property(nonatomic, strong)UIActivityIndicatorView *activityIndicator;
#property (strong, nonatomic) MPMoviePlayerController *moviePlayer;
#end
and here is movieVC.m
#import "movieVC.h"
#import "SWRevealViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#interface movieVC ()
#end
#implementation movieVC
#synthesize link;
#synthesize activityIndicator;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
NSString *urlAddress = link;
//Create a URL object.
NSURL *url1 = [NSURL URLWithString:urlAddress];
self.moviePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url1];
self.moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
self.moviePlayer.view.frame = CGRectMake(0,0,320,180);
[self.view addSubview:_moviePlayer.view];
self.moviePlayer.shouldAutoplay = NO;
[self.moviePlayer setFullscreen:YES animated:YES];
}
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
}
- (void)exitedFullscreen:(NSNotification*)notification {
NSLog(#"exitedFullscreen");
[self.moviePlayer stop];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
break;
default:
break;
}
[self.moviePlayer setFullscreen:NO animated:YES];
}
- (void)showMovie {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
NSString *urlAddress = link;
//Create a URL object.
NSURL *url1 = [NSURL URLWithString:urlAddress];
self.moviePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url1];
self.moviePlayer.view.frame = CGRectMake(0,0,320,180);
[self.view addSubview:_moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
[self.moviePlayer play];
}
-(void)viewWillDisappear:(BOOL)animated {
[self.moviePlayer stop];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Setting up NSMetadataQueryDidUpdateNotification for a simple response

I'm trying to get up and running with an NSMetadataQueryDidUpdateNotification on an OS X app, to alert me when a file in my iCloud ubiquity container is updated. I've been doing a lot of research (including reading other Stack answers like this, this, this, and this), but I still don't have it quite right, it seems.
I've got a "CloudDocument" object subclassed from NSDocument, which includes this code in the H:
#property (nonatomic, strong) NSMetadataQuery *alertQuery;
and this is the M file:
#synthesize alertQuery;
-(id)init {
self = [super init];
if (self) {
if (alertQuery) {
[alertQuery stopQuery];
} else {
alertQuery = [[NSMetadataQuery alloc]init];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
NSLog(#"Notification created");
[alertQuery startQuery];
}
return self;
}
-(void)queryDidUpdate:(NSNotification *)notification {
NSLog(#"Something changed!!!");
}
According to my best understanding, that should stop a pre-existing query if one is running, set up a notification for changes to the ubiquity container, and then start the query so it will monitor changes from here on out.
Except, clearly that's not the case because I get Notification created in the log on launch but never Something changed!!! when I change the iCloud document.
Can anyone tell me what I'm missing? And if you're extra-super-sauce awesome, you'll help me out with some code samples and/or tutorials?
Edit: If it matters/helps, there is only one file in my ubiquity container being synced around. It's called "notes", so I access it using the URL result from:
+(NSURL *)notesURL {
NSURL *url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
return [url URLByAppendingPathComponent:kAllNotes];
}
where "kAllNotes" is set with #define kAllNotes #"notes".
EDIT #2: There have been a lot of updates to my code through my conversation with Daij-Djan, so here is my updated code:
#synthesize alertQuery;
-(id)init {
self = [super init];
if (self) {
alertQuery = [[NSMetadataQuery alloc] init];
if (alertQuery) {
[alertQuery setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSString *STEDocFilenameExtension = #"*";
NSString* filePattern = [NSString stringWithFormat:#"*.%#", STEDocFilenameExtension];
[alertQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, filePattern]];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(queryDidUpdate:) name:NSMetadataQueryDidFinishGatheringNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
NSLog(#"Notification created");
[alertQuery startQuery];
}
return self;
}
-(void)queryDidUpdate:(NSNotification *)notification {
[alertQuery disableUpdates];
NSLog(#"Something changed!!!");
[alertQuery enableUpdates];
}
How do you save your document - what url do you give it? Unless you give it an extension yourself, it won't automatically be given one - so your *.* pattern will never match a file that does not have an extension. Try * as the pattern and see what happens.
Also, it helps to log what is happening within queryDidUpdate, until you've worked out exactly what's going on :
Try something like:
-(void)queryDidUpdate:(NSNotification *)notification {
[alertQuery disableUpdates];
NSLog(#"Something changed!!!");
// Look at each element returned by the search
// - note it returns the entire list each time this method is called, NOT just the changes
int resultCount = [alertQuery resultCount];
for (int i = 0; i < resultCount; i++) {
NSMetadataItem *item = [alertQuery resultAtIndex:i];
[self logAllCloudStorageKeysForMetadataItem:item];
}
[alertQuery enableUpdates];
}
- (void)logAllCloudStorageKeysForMetadataItem:(NSMetadataItem *)item
{
NSNumber *isUbiquitous = [item valueForAttribute:NSMetadataItemIsUbiquitousKey];
NSNumber *hasUnresolvedConflicts = [item valueForAttribute:NSMetadataUbiquitousItemHasUnresolvedConflictsKey];
NSNumber *isDownloaded = [item valueForAttribute:NSMetadataUbiquitousItemIsDownloadedKey];
NSNumber *isDownloading = [item valueForAttribute:NSMetadataUbiquitousItemIsDownloadingKey];
NSNumber *isUploaded = [item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey];
NSNumber *isUploading = [item valueForAttribute:NSMetadataUbiquitousItemIsUploadingKey];
NSNumber *percentDownloaded = [item valueForAttribute:NSMetadataUbiquitousItemPercentDownloadedKey];
NSNumber *percentUploaded = [item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
BOOL documentExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];
NSLog(#"isUbiquitous:%# hasUnresolvedConflicts:%# isDownloaded:%# isDownloading:%# isUploaded:%# isUploading:%# %%downloaded:%# %%uploaded:%# documentExists:%i - %#", isUbiquitous, hasUnresolvedConflicts, isDownloaded, isDownloading, isUploaded, isUploading, percentDownloaded, percentUploaded, documentExists, url);
}
you never allocate your alertQuery....
somewhere you need to alloc,init a NSMetaDataQuery for it
example
NSMetadataQuery* aQuery = [[NSMetadataQuery alloc] init];
if (aQuery) {
// Search the Documents subdirectory only.
[aQuery setSearchScopes:[NSArray
arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// Add a predicate for finding the documents.
NSString* filePattern = [NSString stringWithFormat:#"*"];
[aQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#",
NSMetadataItemFSNameKey, filePattern]];
// Register for the metadata query notifications.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(processFiles:)
name:NSMetadataQueryDidFinishGatheringNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(processFiles:)
name:NSMetadataQueryDidUpdateNotification
object:nil];
// Start the query and let it run.
[aQuery startQuery];
}
processFiles method
== your queryDidUpdate
- processFiles(NSNotification*)note {
[aQuery disableUpdates];
.....
[aQuery enableUpdates];
}
NOTE: disable and reenable search there!
see:
http://developer.apple.com/library/ios/#documentation/General/Conceptual/iCloud101/SearchingforiCloudDocuments/SearchingforiCloudDocuments.html

How to disable MasterView when the keyboard appears in the DetailView

I would like to know if it's possible (and how) when the keyboard appears in the DetailView, to disable any MasterView controls until it disappears. All of this happens in a split view based app of course.
---Update for Prince's solution---
MasterViewController.h
#property (strong, nonatomic) UIView *MasterView;
MasterViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MasterView=self.view;
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
DetailViewController.m
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
((MasterViewController *)self.parentViewController).MasterView.userInteractionEnabled=NO;
return YES;
}
This code as is, crashes the app with an "Unknown Selector" error.
How do i bind delegates; Don't know if that's the problem or not. Any help?
Use UITextField's delegate and also bind delegates:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
MasterView.userInteractionEnabled = NO;
.......
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
MasterView.userInteractionEnabled = YES;
[textField resignFirstResponder];
return YES;
}
I found out a solution!
in MasterView viewDidLoad:
//---registers the notifications for keyboard---
// to see if keyboard is shown / not shown
[[NSNotificationCenter defaultCenter]
addObserver: self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:self.view.window];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
and then...:
//----------Handling Keyboard Appearence---
-(void) keyboardDidShow:(NSNotification *) notification {
[self.tableView setUserInteractionEnabled:NO];
}
//---when the keyboard disappears---
-(void) keyboardDidHide:(NSNotification *) notification {
[self.tableView setUserInteractionEnabled:YES];
}
//---before the View window disappear---
-(void) viewWillDisappear:(BOOL)animated {
//---removes the notifications for keyboard---
[[NSNotificationCenter defaultCenter]
removeObserver: self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}

Drawing NSControl when the windows is key or not

I have a NSControl subview and I want to change the drawing when the control is not on a keyWindow. The problem is that I don't see any property that reflects that state (tried enabled property but that was not it).
In simple terms, can I differentiate between these two states?
You can use NSWindow's keyWindow property, and if you want to check to see if your control is the first responder for keyboard events also test [[self window] firstResponder] == self. I don't believe keyWindow supports KVO, but there is a NSWindowDidBecomeKeyNotification and NSWindowDidResignKeyNotification you can listen for. For instance,
- (id)initWithFrame:(NSRect)frameRect;
{
if ( self = [super initWithFrame:frameRect] )
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(display) name:NSWindowDidResignKeyNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(display) name:NSWindowDidBecomeKeyNotification object:nil];
}
return self;
}
- (void)drawRect:(NSRect)aRect;
{
if ( [[self window] isKeyWindow] )
{
// one way...
}
else
{
// another way!
}
}
- (void)dealloc;
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
[super dealloc];
}

Resources