AVPlayerLayer existing even after the viewDidDisappear method call in iOS - ios

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) {
// ...

Related

How to play an video in an AVPlayer using the videoID for the searched item?

I built an iOS app for showing the video for the searched item, the problem occurred is as follows:
I used the YouTube data api and extracted the videoId.
I am not able to add this to an AVPlayer (but when YouTube player used I was able to add the videoId, for example like this:
[self.playerView loadWithVideoId:self.strngvideoId];
[self.view addSubview:_playerView];
I want to use only AVPlayer and no other players, how can fix this issue?
I want to pass the videoId in the AVPlayer and play the video.
If you want to play the video you have to use AVPlayerViewController.First import AVKit framework in your project.Below code works perfectly.
In ViewController.h I imported the AVKit framework.Before that we need to add in Target->BuildPhases->Link Binary With Libraries
ViewController.h
#import <UIKit/UIKit.h>
#import <AVKit/AVKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) AVPlayerViewController *playerViewController;
- (IBAction)actionPlayVideo:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
NSURL *vedioURL;
}
#end
#implementation ViewController
#synthesize playerViewController;
- (IBAction)actionPlayVideo:(id)sender{
vedioURL =[NSURL fileURLWithPath:strngvideoId];
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:vedioURL];
AVPlayer* playVideo = [[AVPlayer alloc] initWithPlayerItem:playerItem];
playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = playVideo;
playerViewController.player.volume = 0;
playerViewController.view.frame = self.view.bounds;
[self.view addSubview:playerViewController.view];
[playVideo play];
}
Playing Video

addSubView not adding subview

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.

SpriteKit - Return to a persistent scene in the same state it was left in.

The concept of being able to return to a previous scene from where you left off is briefly mentioned here: https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/DesigningGameswithSpriteKit/DesigningGameswithSpriteKit.html
Other than that I can't find any more documentation on the subject. I know in other frameworks like Cocos2D you can pop scenes on a stack, and even have multiple scenes running at the same time.
How do I get this to work in SpriteKit.
I have a game with a swiping menu for character selection. Upon selecting a character the scene changes to another menu. I want users to be able to hit a back button and be presented with the previous scene, where the character they selected is in full view.
At the moment I have it presenting the previous scene as a new one. Which of cause creates it in a fresh state, with the first character in plain view, and not the character they selected.
This should be really simple, but for all my googling, I do not have a clue on how to implement this.
I don't know if anyone is still checking this, but I believe that I have another way to solve the problem.
I made a custom "PauseScene" and the user can set a return scene, meaning that when you are ready to go back, the PauseScene's view presents the return scene. Here's the code:
PauseScene.h
#import "MAScene.h"
#interface PauseScene : MAScene
#property (weak, nonatomic, readonly) SKScene * returnScene;
-(void)setReturnScene:(SKScene *)otherScene;
#end
PauseScene.m
#import "PauseScene.h"
#import "MASpriteButton.h"
#interface PauseScene ()
#property (strong, nonatomic) MASpriteButton * resumeButton;
#end
#implementation PauseScene
-(void)setReturnScene:(SKScene *)otherScene
{
_returnScene = otherScene;
}
-(void)didMoveToView:(SKView *)view
{
[self createContent];
}
-(void)createContent
{
__weak typeof(self) weakMe = self;
MASpriteButton * resume = [[MASpriteButton alloc] initWithBackgroundImageNamed:#"cardback.png" andSelectedImageNamed:#"cardback.png" andCallbackBlock:^{
NSLog(#"removing...");
[weakMe.view presentScene:self.returnScene];
}];
resume.size = CGSizeMake(self.widthToHeightRatio * 20, self.heightToWidthRatio * 20);
resume.position = CGPointMake(self.size.width/2, self.size.height/2);
self.resumeButton = resume;
[self addChild:self.resumeButton];
[self setBackgroundColor:[UIColor blueColor]];
}
#end
The way I used it was that when the user hits a pause button in the gameplay scene, I call these lines:
self.paused = YES;
PauseScene * pScene = [[PauseScene alloc] initWithSize:self.size];
[pScene setReturnScene:self];
[self.view presentScene:pScene];
Note that self in this little block is the gameplay scene.
By having the pause scene keep a weak pointer to the gameplay scene, it can keep a pointer to the return scene without dealloc-ing it when the pause scene is dealloc-ed.
PS The MAScene class is just a little extension of the SKScene class, I just added a couple things to it. If anyone wants that too just let me know.
Assuming the menu scene is also implemented in Sprite Kit, you could create a modal view controller, present it, and put the Sprit Kit scene over that modal view.
So, specifically, create a new UIViewController inheriting class MenuViewController, and a new SKScene inheriting class, MenuScene. The class 'MenuScene' MenuScene should be the Scene you're looking to present. Hook up MenuScene and MenuViewController like you would normally hook up an SKScene and its view controller. Make sure you have the original scene's view controller as a property of the original SKScene.
Wherever you want to present this menu, you can call from the original SKScene:
MenuViewController *modalViewController = [[MenuViewController alloc] init];
[self.viewController presentModalViewController:modalViewController];
There are simpler ways to just transition b/w SKScene instances, but if you want to keep the intial SKScene running in the background, this is what you would have to do, I believe.
You just should keep strong pointer to the leaving scene before you call new
Here is example of realisation via singleton (actually usual singleton with scene pointer, no magic)
#interface Global : NSObject
+ (Global*)sharedInstance;
#property (strong, nonatomic) SKScene *mainScene;
#end
And .m file
#implementation Global
+ (instancetype) sharedInstance{
static Global *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[Global alloc] init];
});
return _sharedInstance;
}
#end

xcode5 - playing sound after pushing button is not working

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;

Why can't I access my superclass methods?

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.

Resources