I have a TableView setup in the storyboard and have a prototype cell that I use to hold images and a button to start videos. The path of the video file is a property in each cell object and I would like to play the video when the button is clicked.
Before I began using the table (when I just had button manually drawn on the storyboard) i used the follow to start the movie player [self presentMoviePlayerViewControllerAnimated:mp]; but obviously now that's not possible.
I'm sure I'm missing something obvious...
The best solution for this is NSNotificationCenter. On Click, in your Cell just send notification with index of your row that you can save in button's tag variable.
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:#"playVideo" forKey:#"operationKey"];
[userInfo setValue: indexPath forKey:#"indexPathRow"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"PlayVideoNotification" object:nil userInfo:userInfo];
In your ViewController register observer:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivePlayVideoNotification:) name:#"PlayVideoNotification" object:nil];
And do not forget unregister observer:
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"PlayVideoNotification" object:nil];
In the method PlayVideoNotification do what you need:
- (void) receivePlayVideoNotification:(NSNotification *) notification
{
NSDictionary *userInfo = notification.userInfo;
NSString *operationKey = [userInfo objectForKey:#"operationKey"];//"playVideo"
NSString* indexPathRow = [userInfo objectForKey:#"indexPathRow"];
//todo
}
I think you should use custom cell to achieve your objective.
You can follow these steps:
Create a new class that is a subclass of UITableViewCell and assign it as the class of your custom cell.
In your custom class .h file make an IBOutlet for your button.
In your main class .m file use this method to play video
- (void)playBtnClicked:(id)sender {
MPMoviePlayerViewController *movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:YourURL];
[self presentMoviePlayerViewControllerAnimated:movieController];
[movieController.moviePlayer play];
}
Use this code after you have configured your cell
[cell.btn_PlayVideo addTarget:self action:#selector(playBtnClicked:) forControlEvents:(UIControlEventTouchUpInside)];
Your should make sure that MediaPlayer.framework is included and MediaPlayer.h file is imported.
As far as I know you have to segue to another ViewController and start the moviePlayerViewController there.
I think you can't just get the IBAction when you click on a TableViewCell.
So try to segue in the InterFaceBuilder, build a ViewController with something like this:
ViewController.h:
#interface ViewController : UIViewController
#property (nonatomic, strong) NSURL *videoFileUrl;
#end
ViewController.m:
#implementation ViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
...
[self presentMoviePlayerViewControllerAnimated:mp];
}
#end
Related
i'm new in IOS. i look for solution for over a day but all available solution work within a single UIViewConntroller but when i did it between uiTableView row selection and UIViewConntroller as Observer then the Selector is not called by Observer.
On row Selection in uitableviewcontroller
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
NSNotification * notification =[[ NSNotification alloc] initWithName:#"NOTIFICATION" object:nil userInfo:dict];
**In UIViewController on viewdidload **
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedNotification:)
name:#"NOTIFICATION" object:nil];
**SelectorAction in uiviewcontroller **
-(void) receivedNotification:(NSNotification*) notification
{
NSLog(#"Notification Received ");
}
hi #Abdul Rehman Warraich, i got your problem. you are posting notification in one view, and trying to observe it an another view. but what happens is, in the second view your observer is not ready (not loaded) to get the notification what you sent.
once you landed in the second view, that time itself observer is loaded.so it obviously will miss the notification.
so whenever you do push and pop, observer will loading as new one. so every time it will fail to observe it.
HINT: Try to load observer in your second view , before you fire the notification.
Hope it will help you to debug.
You don't have to creat a NSNotification object. Just post the notification when row selected :
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
In UITableViewController when you select the row Post Notification:
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
In UIViewController viewDidLoad method addObserver:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedNotification:)
name:#"NOTIFICATION" object:nil];
Write method in UIViewController:
-(void)receivedNotification:(NSNotification*) notification
{
NSLog(#"Notification Received ");
}
Check if UIViewController's instance is there in the stack? otherwise you will not get the response.
There is no problem in any of the above code infect i'm doing it in wrong way. I'm posing notification first and observing after posting notification.
But i have to observe first and post notification after it.
I solve this problem as :
In AppDelegate didFinishLaunchingWithOptions: load viewControler first so that the observer is ready to get notification(inViewDidLoad) and after that Show/navigate to tableView And then it work perfect.This isn't the proper way but work for me. :)
Also Read out the #karthik and #Priyanka Mistry Answers. Helped me to solve the problem.
Use tableView didSelectRowAtIndexPath Delegate:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
//Post notification here
}
Stefos' answer is the usual way to post a notification, but if you do want to create a notification object manually, you then need to post it:
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
NSNotification * notification =[[ NSNotification alloc]
initWithName:#"NOTIFICATION"
object:nil userInfo:dict];
[[NSNotificationCenter defaultCenter] postNotification: notification];
(I don't think I've ever done it in 2 steps like this. I always use one of the forms that takes a name, option, and userInfo and creates and posts the notification in one call.)
Try this i hope it would be helpful:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
myData = [[NSMutableArray alloc]init];
myData = [[NSMutableArray alloc]initWithObjects:#"india",#"Japan",#"pakistan",#"srilanka", nil];
_mytableView.delegate = self;
_mytableView.dataSource = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:)name:#"NOTIFICATION" object:nil];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return myData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *const identifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.textLabel.text = [myData objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * dict =[NSDictionary dictionaryWithObject:#"Ravi" forKey:#"name"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION" object:nil userInfo:dict];
}
-(void) receivedNotification:(NSNotification*) notification {
NSLog(#"Notification Received ");
}
#end
in viewcontroller.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *myData;
}
#property (weak, nonatomic) IBOutlet UITableView *mytableView;
#end
In my app in which I'm using storyboards I have mainViewController with MapView inside. At the top of the mainViewController I'm displaying UIContainerView from the bottom of the screen with UITableViewController inside. When user click on row I'm sending notification to the mainViewController in purpose of changing map region with animation. The similar notifications are sending when user is selecting specific tableViewCell and also when user tapping on the DONE button located in navigationViewController. Everything works fine for me except method called in DONE button method.
MAIN VIEW CONTROLLER -(void)viewDidLoad method...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(hideContainerView:)
name:HideContainerView object:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeRegionForUser:)
name:ChangeRegionForUser
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(hideContainerView:)
name:ChangeRegionToInitial
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeRegionToFitWearerAnnotations:)
name:ChangeRegionToFitWearerAnnotations
object:nil];
MAIN VIEW CONTROLLER OBSERVERS METHODS:
#pragma mark NSNotificationCenter methods
-(void)changeRegionForUser:(NSNotification*)notification
{
NSLog(#"%#",notification.description);
[self zoomToFitUserLocationWithLatitude:-33.861858 longitude:151.210546 andUserInfo:nil];
}
-(void)hideContainerView:(NSNotification*)notification
{
NSLog(#"%#",notification.description);
[self zoomToFitMapAnnotations:_mainMapView];
[UIView beginAnimations:#"HideContainerAnimation" context:nil];
[UIView setAnimationDuration:0.5];
[_containerView setFrame:CGRectMake(0, 600, 320, 284)];
[UIView commitAnimations];
}
-(void)changeRegionToFitWearerAnnotations:(NSNotification*)notification
{
NSLog(#"%#",notification.description);
[self zoomAnnotationsOnMapView:_mainMapView toFrame:CGRectMake(0, 0, 320, 200) animated:YES];
}
TABLE VIEW CONTROLLER (DID-SELECT-ROW-AT-INDEX-PATH METHOD)//It work properly
[[NSNotificationCenter defaultCenter] postNotificationName:#"ChangeRegionForUser" object:self];
TABLE VIEW CONTROLLER (DONE BUTTON METHOD) //IT DOESN'T WORK
-(void)doneButtonAction:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"HideContainerView" object:self];
}
MY STORYBOARD
IN MAIN VIEW CONTROLLER.H
#interface MainScreenViewController : UIViewController<MKMapViewDelegate>
extern NSString * const HideContainerView;
extern NSString * const ChangeRegionForUser;
extern NSString * const ChangeRegionToInitial;
extern NSString * const ChangeRegionToFitWearerAnnotations;
IN MAIN VIEW CONTROLLER.M
#import "MainScreenViewController.h"
NSString* const HideContainerView = #"HideContainerView";
NSString* const ChangeRegionForUser = #"ChangeRegionForUser";
NSString* const ChangeRegionToInitial = #"ChangeRegionToInitial";
NSString* const ChangeRegionToFitWearerAnnotations =#"ChangeRegionToFitWearerAnnotations";
You are using a string constant HideContainerView for the notification name when you add yourself as observer. But when you post the notification you are using a literal string #"HideContainerView". Maybe you are using two different strings there?
Also, I think that you are using self as the object when you add yourself as an observer. It seems this precludes receiving the notification. From the documentation:
notificationSender
The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.
If you pass nil, the notification center doesn’t use a notification’s sender to decide whether to deliver it to the observer.
Use nil instead.
That being said, would it not be better to couple these two controllers more tightly. I think that would be a much more appropriate design. You should send notifications when the sender does not know if the receiver exists or not. But in this case, you know that the receiver exists.
Thus, you should implement a simple delegate protocol, retain a reference to the map view controller and tell it directly what to do.
Sorry for the basic Question, I'm fairly new to programming and trying to understand something in the code apple suggester for a certain solution to something I wanted to preform.
I created a simple notes app, very basic, currently I have:
1. CreateNote view controller
2. NotesList table view controller
So I wanted to add a behaviour when a note is being created and a user types below the keyboard so the text resized so the user can still see what he types and the text is not going behind the keyboard.
So I add some lines of code suggested by apple to accomplish that.
In the viewWillAppear called a method on NSNotificationCenter and I could not understand where is an NSNotificationCenter object is declared...?
So this is my CreateNote view controller(Please help me understand why they could preform this call):
#import "NMCreateNotesViewController.h"
#interface NMCreateNotesViewController () <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *createButton;
#property (weak, nonatomic) IBOutlet UITextView *textField;
#end
#implementation NMCreateNotesViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
#pragma mark - Notifications
- (void)adjustViewForKeyboardReveal:(BOOL)showKeyboard notificationInfo:(NSDictionary *)notificationInfo
{
// the keyboard is showing so resize the table's height
CGRect keyboardRect = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.textField.frame;
// the keyboard rect's width and height are reversed in landscape
NSInteger adjustDelta = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? CGRectGetHeight(keyboardRect) : CGRectGetWidth(keyboardRect);
if (showKeyboard)
frame.size.height -= adjustDelta;
else
frame.size.height += adjustDelta;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.textField.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:YES notificationInfo:[aNotification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:NO notificationInfo:[aNotification userInfo]];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.createButton) return;
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
self.note.content = self.textField.text;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Is NSNotificationCenter is part of UITextView?
No it is not. NSNotificationCenter is - as it's name says - a notification center. Objects can subscribe to notifications and post notifications with NSNotificationCenter to handle and notify of certain events.
They are using NSNotificationCenter to have the viewcontroller subscribe to UIKeyboardWillHideNotification and UIKeyboardWillShowNotification events.
Take a look at this one:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
NSNotificationCenter is designed to be used as a singleton ( I believe this is the correct term, correct me if I'm wrong ) so we access the NSNotificationCenter for this app's process by calling the class method defaultCenter. it adds observer 'self' ( which in this case is an instance of the view controller) and basically instructs it to send the message keyboardWillShow to the observer when a Notification under the name of UIKeyboardWillShowNotification is fired.
What object fires the UIKeyboardWillShowNotification? Well it's not a UITextView, this notification name is actually defined in UIWindow.h so it probably came from there, which in turn probably was invoked from UIKeyboard which is not a public API as far as I know.
NSNotificationCenter is a class. In Objective-C, classes are declared in header files; this one is in NSNotification.h. (Try pressing Command-Shift-O and typing "NSNotificationCenter" to find this yourself.) When you want to use a class, you #import the header file that the class is declared in; this makes the compiler read that header file first and make all the classes (and other globals) available to your code to use.
This would be a huge pain, though, since a typical Cocoa app uses zillions of classes and other globals from Apple's libraries. So, instead, you just need to #import <Foundation/Foundation.h> which is a header file that just includes a bunch of other header files, including NSNotification.h. (The import statement for Foundation is probably in your own header file, or something else like #import <UIKit/UIKit.h> which also will include foundation and ultimately NSNotification.h.)
One final detail is that there's is probably a "prefix" header in your project which includes UIKit.h in all of your files automatically, so anything declared in there is always available to your code.
NSNotificationCenter is a class in Foundation.
NSNotificationCenter doesn't need to be declared and stored in a variable, its just a call, to explain it further, think of NSNotificationCenter as a tackboard where things get posted, you add a note to that backboard by creating the NSNotificationCenter, and you assingn observers to look at that board, and do something when a note is added.
The NSNotificationCenter object being used in this case is a Singleton. What you need to know is that sending the message defaultCenter to the NSNotificationCenter class object always returns the same NSNotificationCenter object.
Here's what the call to default center might look like
+ (NSNotificationCenter*)defaultCenter
{
static dispatch_once_t once;
static NSNotificationCenter* sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
/*
set up properties, etc
*/
});
return sharedInstance;
}
I have in my app a UITableview Controller, a View Controller and I'm trying to pass NSDictionary from UITableview Controller to my ViewController, using NSNotificationCenter. So, I push a notification at my UITableview Controller and then I add an observer ,using a selector at my ViewController.The selector is called,but I have an NSLog and get memory results ,like :
ViewController: 0x8a0bcc0
I have tried to pass NSString instead of NSDictionary , but I get again memory results , and not the value of the string.
My code :
UITableView Controller
NSString *string=#"This is a test string";
[[NSNotificationCenter defaultCenter] postNotificationName: #"Update" object: string];
ViewController
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"Update" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self];
And here is the incomingNotification selector method:
-(void) incomingNotification : (NSNotification *)notification{
NSLog(#"Trying to print : %#",[notification object]);
}
All Notifications take place at ViewDidLoad method.Thank you!
UPDATE
Finally , I quit using NSNotificationCenter and used properties to pass data ,changing a bit the inheretence from my TableViewController. No idea why Notifications did not work ,as they were supposed to. Thank you all ,very much for your suggestions and ideas :)
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self]
Object means the object that generates a notification. To post parameters use another method
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self userInfo:string]
If I understand correctly, UIViewController is shown after you tap a button on UITableViewController. And you if you are adding a ViewController as observer in its -viewDidLoad:, then it will be able to receive notifications only when it is loaded.
What do you need:
1) override -init or -initWithNibName: method of ViewController like this:
-(id) init
{
self = [super init];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(incomingNotification:) name:#"Update" object:nil];
}
return self;
}
so you can be sure ViewController is observing for notifications from the beginning (well, this might be unnecessary step for your case)
2) when you push ViewController you need to send a notification after it was created, like this:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewController *nextController = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nextController animated:YES];
NSString *string=#"This is a test string";
[[NSNotificationCenter defaultCenter] postNotificationName: #"Update" object: string];
}
However, if you're trying just to send some parameters from one view controller to another, this is the wrong way. Just create a property in ViewController and in method -tableView:didSelectRowAtIndex: of UITableViewController set this property
I am using push notifications in my code and whenever a notification comes, I want to update the value of a label in another ViewController.
My code in AppDelegate is:
- (void)addMessageFromRemoteNotification:(NSDictionary*)userInfo updateUI:(BOOL)updateUI
{
NSLog(#"Notification arrived");
//[mydeals setCode1_id:mydeals.code1_id withString:#"123456"];
mydeals=[[MyDealsViewController alloc]init];
NSDictionary* codeDetails=[[NSDictionary alloc] initWithObjectsAndKeys:#"123456",#"Code_id", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CodeArrived" object:self userInfo:codeDetails];
}
then in my other view controller I have this code:
#implementation MyDealsViewController
-(id) init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveCode:)
name:#"CodeArrived"
object:nil];
return self;
}
-(void) receiveCode:(NSNotification*)notification
{
NSLog(#"received Code: %#",notification.userInfo);
self.code1_id.text=[NSString stringWithFormat:#"%#",[[notification userInfo] valueForKey:#"Code_id"]];
}
the log is printed correctly but when I manually go into that screen I see the default value, like the label is not updated at all. What should I do?
You have to make sure that when you "manually go" to MyDealsViewController, whatever how you do it, it got to be the same instance of MyDealsViewController wich has been called receiveCode. Otherwise it's going to init with it's default values.
You might also try calling [self.code1_id setNeedsLayout];