I'm using LBYouTubePlayer to play videos in my app.
In the framework LBYouTubePlayer, it's subclassed as mpmovieplayercontroller, declared as
#interface LBYouTubePlayerViewController : MPMoviePlayerViewController
In my own view controller, I do
#property (nonatomic, strong) LBYouTubePlayerViewController* videoPlayerController;
and video plays successfully with
self.videoPlayerController = [[LBYouTubePlayerViewController alloc] initWithYouTubeID:stringID quality:LBYouTubeVideoQualitySmall];
self.videoPlayerController.delegate = self;
[self.viewForPlayer addSubview:self.videoPlayerController.view];
but when I try
[self.videoPlayerController setControlStyle: MPMovieControlStyleDefault ];
the method isn't recognized? even when I do self.videoPlayerController, autocomplete pops up but does not show any of the superclass' methods?
There is no in setControlStyle method in MPMoviePlayerViewController.
Related
In my application, I'm using AVPlayer to play a YouTube video with the help of HCYoutubeParser library.
My question is, when I load a new view controller I still can hear the sound of the played video file.
I tried to load the next view two different methods but still having the same result.
Method 1
FourthViewController *fourthViewCont = [self.storyboard instantiateViewControllerWithIdentifier:#"FourthViewControllerID"];
[self.navigationController pushViewController:fourthViewCont animated:YES];
Method 2
Using storyboard segue
I can get rid of this problem by adding following code inside the viewDidDisappear method
[avPlayerLayer removeFromSuperlayer];
avPlayerLayer = nil;
But what I need to know is even when the view is disappeared why the avPlayerLayer instance having a reference?
I am adding the player layer like below
[_playerContainerView.layer addSublayer:avPlayerLayer];
_playerContainerView is not the main UIView but a UIView located inside the main UIView.
I have declared AVPlayerLayer variable in the class extension like below
#interface PlayerViewController ()
{
AVPlayerItem *avPlayerItem;
AVPlayerLayer *avPlayerLayer;
}
and also AVPlayer and the container view has weak refeences
#property (weak, nonatomic) AVPlayer *avPlayer;
#property (weak, nonatomic) IBOutlet UIView *playerContainerView;
My confusion increase more with the following scenario, which is when I going back from PlayerViewController to my previous view, the player stops correctly without any background audio sound.
Can anybody explain this situation?
Edit :
This is how I initialized the AVPlayer and AVPlayerLayer
_avPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem];
avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:_avPlayer];
After these initialization I added sublayer and all these codes inside the completion block
[HCYoutubeParser h264videosWithYoutubeURL:youtubeUrl completeBlock:^(NSDictionary *videoDictionary, NSError *error) {
// ...
I have an app that should display a Youtube video and I'm using the Youtube ios helper API.
I have a subclass of UITabBarController that is used to present two youtube videos and the UITabBarController is inside a NavController and is pushed to from a UITableViewController. So the setup looks like
[NAVController] -- relationship --> [UITableViewController] -- push --> [UITabBarController] -- relationship --> [CustomViewController]
Now my CustomViewController.h looks like:
#import <UIKit/UIKit.h>
#import "YTPlayerView.h"
#interface CustomViewController : UIViewController<YTPlayerViewDelegate>
#property (strong, nonatomic) YTPlayerView *youtubeView;
#property (strong, nonatomic) NSString *videoID;
#end
and my .m file has
#import "CustomViewController.h"
#import "YTPlayerView.h"
#interface CustomViewController ()
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
NSLog(#"Subviews %lu", (unsigned long)[self.view.subviews count]);
NSLog(#"Subviews %#", self.views.subviews);
BOOL b = [self.youtubeView loadWithVideoId:self.videoID];
NSLog(#"Loaded? %d", b);
[self.youtubeView playVideo];
}
What I end up with is a navigation bar at the top (as it should be), a tab bar at the bottom (as it should be), but with a blue background instead of a red background (and needless to say, no Youtube video loads). When I run this, it prints
Subviews 0
Subviews (
)
Loaded? 0
Clearly the addSubView: call is not working.
I've seen this post, but it didn't help.
(For those unfamiliar with the youtube ios helper library:
The youtube-ios-player-helper is an open source library that helps you embed a YouTube iframe player into an iOS application. The library creates a UIWebView and a bridge between your application’s Objective-C code and the YouTube player’s JavaScript code, thereby allowing the iOS application to control the YouTube player.
(Using iOS 7 and Xcode 5.1)
Since I don't see that you're using an IBOutlet, I believe you need to initialize the self.youtubeView:
self.youtubeView = [[YTPlayerView alloc]init];
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
The YouTube api isn't the problem here, UINavigation controller and UITabBarController just dont play nicely together. What you should do instead is make a view controller to handle the tabbar instead of a UITabBarController. This shows some insight on how to get it done.
I am quite new to Obj C and iOS development and I have come across an issue to which I have no understanding why it is happening.
So to set the scene, I have 2 model classes, Player and Computer Player and a Controller.
Player:
#interface Player : NSObject
-(void) playerMessage;
#end
ComputerPlayer:
#interface ComputerPlayer : Player
-(void) computerPlayerOnlyMessage;
#end
Controller:
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
[currentPlayer computerPlayerOnlyMessage];
}
However the issue with the above is [currentPlayer computerPlayerOnlyMessage] gives a complier error when ARC is turned on. When ARC is turned off it gives a compiler warning but will run as I would expect it too.
Any help is appreciated to get help me figure why this behaviour is happening.
Isn't it better to define:
- (void)playerMessage;
method in ComputerPlayer class and:
-(void)playerMessage {
[super playerMessage];
[self computerOnlyPlayerMessage];
}
That's a point of inheritance, isn't it? You defined (expecting) your class variable as Player but NOT ComputerPlayer, and if it is ComputerPlayer it will execute specific work only for "computer".
Of course then you execute:
[Player playerMessage]; // Warning should gone
You can test, if it is a computer player
if ([currentPlayer isKindOfClass:[ComputerPlayer class]])
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
It gives you an error because p2 is subclass of Player and you haven't for such a method as computerPlayerOnlyMessage in Player class. This method exists in ComputerPlayer class so you should declare p2 as a object of this type. Chenge line where you declare p2 to:
ComputerPlayer *p2;
First instead of declaring them as ivars like
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
do it with #properties. The reason being is that ivars don't have any getters or setters whereas they are automatically generated if you use '#properties so change to
#interface viewController : UIViewController
// This will auto generate the ivars, getters and setters
#property (nonatomic, strong) Player *p1;
#property (nonatomic, strong) Player *p2;
#property (nonatomic, strong) Player *currentPlayer;
#end
then you can do
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
// Could also replace below with [currentPlayer isKindOfClass:[ComputerPlayer class]] use which ever fits best for you and what you want.
// If using below, if you decided to subclass ComputerPlayer class anything that subclassed
// from ComputerPlayer will also make it into this if statement. If iskindOfClass: is used
// Only objects that are kind of class will make it into this if statement.
if([[currentPlayer class] isSubclassOfClass:[ComputerPlayer class]]) {
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
}
}
As #Greg said, computerPlayerOnlyMessage is a method exposed by the ComputerPlayer class, not the class it inherits from, so even if the compiler reports a warning when ARC is disabled, it would be a bad practice to use it.
Explicitly asking the class instance if it implements that method it's a workaround that works though. However in my opinion that solution lacks of good OO design, and I wouldn't use it unless I have a good reason (there are cases when it is handy) - in other OO languages that wouldn't event be possible.
Polymorphism allows an instance of a class to be used as if it were one of its super classes, but not the opposite. You can override and specialize the superclass methods, but you cannot expect a superclass to be aware of methods implemented by any of its subclasses.
I suggest 2 possible solutions:
declare computerPlayerOnlyMessage in the Player class as abstract (with empty body or throwing an exception, acting as a reminder that the method should be overriden in subclasses)
remove computerPlayerOnlyMessage from ComputerPlayer and instead override playerMessage. Thanks to polymorphism, the correct implementation will be called, regardless of whether you are accessing to the class instance as Player or ComputerPlayer
If computerPlayerOnlyMessage is meant to do what playerMessage does, just in a different way, I'd choose option no. 2
This seems like a good place to use protocols.
Here's how I might write your example, where I need to send "player" messages to all instances of Players, specialize on occasion, and send specific "npc" messages other times.
#protocol <NPC>
#property (nonatomic) NSString *someNPCString;
- (void)foo;
- (void)bar;
#end
#interface Player : NSObject
#end
#implementation Player
- (void)message
{
NSLog(#"message");
}
#end
#interface AI : Player <NPC>
#end
#implementation AI
#synthesize someNPCString;
- (void)foo
{
NSLog(#"foo");
}
- (void)bar
{
NSLog(#"bar");
}
#end
#interface viewController : UIViewController
#property (nonatomic) NSArray *humans;
#property (nonatomic) NSArray *npcs;
#end
#implmentation ViewController
-(void)viewDidLoad
{
id<Player> currentPlayer = nil;
humans = [NSArray arrayWithObject:[Player new]];
npcs = [NSArray arrayWithObjects:[AI new], [AI new], nil];
// message all player types, regardless of player or npc
for (Player *player in [humans arrayByAddingObjectsFromArray:npcs])
{
currentPlayer = player;
[player message];
if([player conformsToProtocl:#protocol(NPC)])
{
[(id<NPC>)player foo];
}
}
for (id<NPC>npc in npcs)
{
[npc bar];
npc.someNPCstring = #"str";
}
}
As you can see, this lets you treat npcs like human players, if you need to, let's you ask if the player conforms to the NPC protocol, so you may call the required protocol methods, and let's you reference objects specifically by their protocol.
Protocols begin to make the most sense, in my humble opinion, when you begin to need to "mix in" behavior to various objects.
OBJECTIVE :
I am trying to get a sound to play when a button is clicked. This sound will be preformed by an action called "play". The sound is in my resource folder and is called SoftClick.mp3
PROBLEM:
There is no sound at all being played in either simulator or the real device. The code does not give any errors.
CONNECTIONS:
The button, that needs to give sound, is connected to the action play and is used as a Modal Segue to show another view controller. Both viewcontrollers use the same .h and .m script.
CODE FOR .H
#import <UIKit/UIKit.h>
#import<AVFoundation/AVAudioPlayer.h>
#interface ViewController : UIViewController
{
AVAudioPlayer *audioPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *audioPlayer;
- (IBAction) play;
#end
Action and audioplayer are defined as i thought was necessary (?)
THE CODE FOR .M
#import "ViewController.h"
#import<AVFoundation/AVAudioPlayer.h>
#interface ViewController ()
#end
#implementation ViewController
#synthesize audioPlayer;
-(IBAction)play
{
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"SoftClick"ofType:#"mp3"]] error:NULL];
[theAudio play];
}
Can someone please help me with correcting my coding so this could work in xcode5?
Ive spend some hours trying to figure out why this will not work an tried combinations like without segue etc. I do not want to steal the code from someone else and am trying to build this on my own.
Thanks in advanced,
Lien
The issue, as I'm assuming you're using ARC, is that you aren't retaining the AVAudioPlayer object. You create the object, call play, but then it is instantly released and dealloc'd. You need to add self.audioPlayer = theAudio;
I am programming a Quiz-App. In the Menu-ViewController I added Music to the project. The musicPlayer is running well and as long as the Menu-ViewController is in front, I can also controle it (play, pause, stop, ect.). When I display another ViewController, the Music runs in the Background, like I'd like to. But if try to call the play/pause Method of the first ViewController being in the secondViewController, the music nether paused nor stoped. I don't know why! If I add other Instructions to this Method, everything's going fine. (I tried the exit(0); Method. Here is my Code:
Controller 1 .h :
#implementation MenuViewController : <....> {
... }
#property (retain) AVAudioPlayer *backgroundPlayer;
- (void) playPauseMethod;
Controller 1 .m :
#interface ...
#end
#implementation MenuViewController
# synthesize
- (void) soundChanger {
if (hintergrundPlayer.isPlaying) {
[backgroundPlayer pause];}
else if (!backgroundPlayer.isPlaying) {
[backgroundPlayer play];}}
Controller 2 .h :
#import "MenuViewController.h"
#interface QuizViewController : UIViewController{}
Controller 2 .m :
#interface ...
#end
#implementation MenuViewController
# synthesize ...
//..... musicPlayer is playing music.
- (IBAction)myMusic:(id)sender {
//first try:
[[[MenuViewController alloc] init].backgroundPlayer pause];
//second try:
[[[MenuViewController alloc] init] soundChanger];}
I'd like to control the music in every ViewController. I'm looking forward to your help.
You're creating a completely new MenuViewController in Controller2 with
[[MenuViewController alloc] init]
The best way to handle it would be to set up a protocol in controller 2 with something like
#protocol <Controller2Delegate>
-(void) playButtonPressed:(id)self;
#end
Then set up a delegate property (still in controller 2) like this:
#property (weak) id <Controller2Delegate> delegate;
Then, back in Controller 1, when you create the Controller 2, set it's delegate property, like this:
QuizViewController *controller2 = [[QuizViewController alloc] init]];
controller2.delegate = self;
And then create the playButtonPressed method somewhere in controller 1. From Controller 2, you'll do something like:
[self.delegate playButtonPressed:self];
And that will call the method in Controller 1, where you can pause the background player.