My code was working perfectly some months ago. i dint chnage anything
I dont understand why the didRangeBeacons in Region not trigger when i launch my app :
#import "ESTViewController.h"
#import "PresentViewController.h"
#import <ESTBeaconManager.h>
#import <Parse/Parse.h>
#import <AudioToolbox/AudioToolbox.h>
#interface ESTViewController () <ESTBeaconManagerDelegate>
#property (nonatomic, strong) ESTBeaconManager* beaconManager;
#property (nonatomic, strong) ESTBeacon* selectedBeacon;
#property (nonatomic, strong) NSArray *beaconsArray;
#end
#implementation ESTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// setup Estimote beacon manager.
// Create the manager instance.
self.beaconManager = [[ESTBeaconManager alloc] init];
// Setup the delegate
self.beaconManager.delegate = self;
// Avoiding unknown state or not
self.beaconManager.avoidUnknownStateBeacons = NO;
// create sample region object (beacons in this case have all same uuid and same major)
region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID identifier:#"multibeacons"];
[self.beaconManager requestStateForRegion:region];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// start looking for estimote beacons in region
// when beacon ranged beaconManager:didRangeBeacons:inRegion: invoked
[self.beaconManager startRangingBeaconsInRegion:region];
[self.beaconManager startMonitoringForRegion:region];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// stop looking for estimote beacons in region
[self.beaconManager stopRangingBeaconsInRegion:region];
[self.beaconManager stopMonitoringForRegion:region];
}
#pragma mark - ESTBeaconManager delegate
-(void)beaconManager:(ESTBeaconManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(ESTBeaconRegion *)region
{
// descriptor on distance to sort the array of beacons by distance
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
// sorting the array of beacons
// beacon array is sorted based on distance
// closest beacon is the first one
self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors];
if([self.beaconsArray count] > 0)
{
if(!self.selectedBeacon)
{
// initialy pick closest beacon
self.selectedBeacon = [beacons objectAtIndex:0];
currentBeaconMinor = self.selectedBeacon.minor;
}
else
{
//sorting the array of beacons
self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors];
//updating the selected beacon with the first element of the array (closest beacon)
if(self.selectedBeacon != [beacons objectAtIndex:0] )
{
self.selectedBeacon = [beacons objectAtIndex:0];
currentBeaconMinor = self.selectedBeacon.minor;
}
}
// Switch on proximity of the closest beacon
switch (self.selectedBeacon.proximity)
{
case CLProximityUnknown:
{
self.rangeStatusImageView.image = [UIImage imageNamed:#"lost.jpg"];
self.rangeStatusImageView.hidden = NO;
self.signalStatusImageView.hidden = YES;
self.descriptionStateLabel.text = #"Recherche de signal ... Si le problème persiste, contactez l'accueil";
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.rangeStatusImageView.alpha = 0.3;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0
delay: 0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.rangeStatusImageView.alpha = 1.0;
}
completion:nil];
}];
break;
}
case CLProximityImmediate:
{
if ([currentBeaconMinor floatValue] == 128)
{
NSLog(#"128 128 128");
[self performSegueWithIdentifier: #"presentSegue1" sender: self];
}
else if ([currentBeaconMinor floatValue] == 228)
{
NSLog(#"228 228 228");
[self performSegueWithIdentifier: #"presentSegue2" sender: self];
}
else if ([currentBeaconMinor floatValue] == 328)
{
NSLog(#"328 328 328");
[self performSegueWithIdentifier: #"presentSegue3" sender: self];
}
break;
}
case CLProximityNear:
{
self.rangeStatusImageView.image = [UIImage imageNamed:#"near.jpg"];
self.signalStatusImageView.hidden = NO;
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.rangeStatusImageView.alpha = 0.3;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0
delay: 0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.rangeStatusImageView.alpha = 1.0;
}
completion:nil];
}];
self.rangeStatusImageView.hidden = NO;
self.descriptionStateLabel.font = [UIFont systemFontOfSize:17];
self.descriptionStateLabel.text = #"Approchez vous d'un article pour obtenir plus d'informations";
break;
}
case CLProximityFar:
{
self.rangeStatusImageView.image = [UIImage imageNamed:#"far.jpg"];
[self.rangeStatusImageView stopAnimating];
self.rangeStatusImageView.hidden = NO;
self.signalStatusImageView.hidden = NO;
self.descriptionStateLabel.text = #"Bienvenue dans notre ... ";
break;
}
default:
break;
}
self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors];
}
}
i have a break point at the line after the pragma mark , it never reach that code. I really dont understand why.
Thanks for your help.
I found a solution :
i updated the Info.plist file with :
<key>NSLocationAlwaysUsageDescription</key>
<string>This application monitors your location to show you promotional offers in shops you're passing by.</string>
In the iphone i have change the settings for localisation for my app to "always"
Related
I'm having difficulty playing back video that I've recently recorded in a hybrid image/video camera akin to Snapchat (e.g. tap to take a photo, press and hold to record a video, playback on button release).
I'm currently saving the video file to NSFileManager. When I log it out I do verify that something is being saved but can't inspect the file because it has to be tested on the phone.
The file path when I log it out:
file:///var/mobile/Containers/Data/Application/7D86B14D-ACFF-4494-AD61-CBBD32DCA7A5/Documents/test.mov
When I go to load the asset from the file manager I log out an error that it can't open the files. I've only just started working with AVFoundation so not sure what some of the issues/considerations are when debugging. Any insight would be greatly appreciated, thank you!
Referenced tutorial
Referenced github repository
Referenced code:
PlayerView.h (reference)
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface PlayerView : UIView
#property (nonatomic) AVPlayer *player;
- (void)setPlayer:(AVPlayer *)player;
#end
PlayerView.m (reference)
#import "PlayerView.h"
#implementation PlayerView
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer *)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
#end
HybridCameraViewController.h (reference)
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "PlayerView.h"
#interface HybridCameraViewController : UIViewController
#property UIButton *button;
#property UIButton *saveButton;
#property UIImageView *previewView;
#define VIDEO_FILE #"test.mov"
#end
HybridCameraViewController.m (reference)
#import "HybridCameraViewController.h"
static const NSString *ItemStatusContext;
#class PlayerView;
#interface HybridCameraViewController () <AVCaptureFileOutputRecordingDelegate>
#end
#implementation HybridCameraViewController
AVCaptureSession *session;
AVCaptureStillImageOutput *imageOutput;
AVCaptureMovieFileOutput *movieOutput;
AVCaptureConnection *videoConnection;
AVPlayer *player;
AVPlayerItem *playerItem;
PlayerView *playerView;
- (void)viewDidLoad {
[super viewDidLoad];
[self testDevices];
self.view.backgroundColor = [UIColor blackColor];
//Image preview
self.previewView = [[UIImageView alloc]initWithFrame:self.view.frame];
self.previewView.backgroundColor = [UIColor whiteColor];
self.previewView.contentMode = UIViewContentModeScaleAspectFill;
self.previewView.hidden = YES;
[self.view addSubview:self.previewView];
//Playerback setup
playerView = [[PlayerView alloc]initWithFrame:self.view.frame];
playerView.backgroundColor = [UIColor redColor];
[self syncUI];
//Buttons
self.button = [self createButtonWithTitle:#"REC" chooseColor:[UIColor redColor]];
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPressGesture:)];
[self.button addGestureRecognizer:longPressRecognizer];
[self.button addTarget:self action:#selector(captureImage) forControlEvents:UIControlEventTouchUpInside];
self.saveButton = [self createSaveButton];
[self.saveButton addTarget:self action:#selector(saveActions) forControlEvents:UIControlEventTouchUpInside];
}
- (void)viewWillAppear:(BOOL)animated {
//Tests
[self initializeAVItems];
NSLog(#"%#", videoConnection);
NSLog(#"%#", imageOutput.connections);
NSLog(#"%#", imageOutput.description.debugDescription);
}
#pragma mark - AV initialization
- (void)initializeAVItems {
//Start session, input
session = [AVCaptureSession new];
if ([session canSetSessionPreset:AVCaptureSessionPresetHigh]) {
session.sessionPreset = AVCaptureSessionPresetHigh;
}
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
if ([session canAddInput:deviceInput]) {
[session addInput:deviceInput];
} else {
NSLog(#"%#", error);
}
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:session];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//Layer preview
CALayer *viewLayer = [[self view] layer];
[viewLayer setMasksToBounds:YES];
CGRect frame = self.view.frame;
[previewLayer setFrame:frame];
[viewLayer insertSublayer:previewLayer atIndex:0];
//Image Output
imageOutput = [AVCaptureStillImageOutput new];
NSDictionary *imageOutputSettings = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
imageOutput.outputSettings = imageOutputSettings;
//Video Output
movieOutput = [AVCaptureMovieFileOutput new];
[session addOutput:movieOutput];
[session addOutput:imageOutput];
[session startRunning];
}
- (void)testDevices {
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice *device in devices) {
NSLog(#"Device name: %#", [device localizedName]);
if ([device hasMediaType:AVMediaTypeVideo]) {
if ([device position] == AVCaptureDevicePositionBack) {
NSLog(#"Device position : back");
}
else {
NSLog(#"Device position : front");
}
}
}
}
#pragma mark - Image capture
- (void)captureImage {
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in imageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"Requesting capture from: %#", imageOutput);
[imageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:imageData];
self.previewView.image = image;
self.previewView.hidden = NO;
}
}];
[self saveButtonFlyIn:self.saveButton];
}
#pragma mark - Video capture
- (void)captureVideo {
NSLog(#"%#", movieOutput.connections);
[[NSFileManager defaultManager] removeItemAtURL:[self outputURL] error:nil];
videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:movieOutput.connections];
[movieOutput startRecordingToOutputFileURL:[self outputURL] recordingDelegate:self];
}
- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections {
for (AVCaptureConnection *connection in connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:mediaType]) {
return connection;
}
}
}
return nil;
}
#pragma mark - Show Last Recording
- (void)presentRecording {
NSLog(#"unplaying");
NSLog(#"%#",[self outputURL]);
}
- (IBAction)loadAssetFromFile {
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[self outputURL] options:nil];
NSString *tracksKey = #"tracks";
[asset loadValuesAsynchronouslyForKeys:#[tracksKey] completionHandler:^{
dispatch_async(dispatch_get_main_queue(),^{
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey
error:&error];
if (status == AVKeyValueStatusLoaded) {
playerItem = [AVPlayerItem playerItemWithAsset:asset];
[playerItem addObserver:self forKeyPath:#"status"
options:NSKeyValueObservingOptionInitial
context:&ItemStatusContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:playerItem];
player = [AVPlayer playerWithPlayerItem:playerItem];
[playerView setPlayer:player];
}
else {
NSLog(#"The asset's tracks were not loaded:\n%#", [error localizedDescription]);
}
});
}];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == &ItemStatusContext) {
dispatch_async(dispatch_get_main_queue(),^{
[self syncUI];
});
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[player seekToTime:kCMTimeZero];
}
- (void)syncUI {
if ((player.currentItem != nil) &&
([player.currentItem status] == AVPlayerItemStatusReadyToPlay)) {
self.button.enabled = YES;
}
else {
self.button.enabled = NO;
}
}
#pragma mark - AVCaptureFileOutputRecordingDelegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
if (!error) {
NSLog(#"Success!!!!");
} else {
NSLog(#"Error: %#", [error localizedDescription]);
}
}
#pragma mark - Recoding Destination URL
- (NSURL *)outputURL {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:VIDEO_FILE];
return [NSURL fileURLWithPath:filePath];
}
#pragma mark - Buttons
- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSLog(#"Press");
self.button.backgroundColor = [UIColor greenColor];
[self captureVideo];
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
NSLog(#"Unpress");
self.button.backgroundColor = [UIColor redColor];
[movieOutput stopRecording];
[self performSelector:#selector(loadAssetFromFile)];
[player play];
}
}
- (UIButton *)createButtonWithTitle:(NSString *)title chooseColor:(UIColor *)color {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(self.view.center.x, self.view.frame.size.height - 100, 85, 85)];
button.layer.cornerRadius = button.bounds.size.width / 2;
button.backgroundColor = color;
button.tintColor = [UIColor whiteColor];
[self.view addSubview:button];
return button;
}
- (UIButton *)createSaveButton {
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(self.view.frame.size.width, self.view.frame.size.height - 100, 85, 85)];
button.layer.cornerRadius = button.bounds.size.width / 2;
button.backgroundColor = [UIColor greenColor];
button.tintColor = [UIColor whiteColor];
button.userInteractionEnabled = YES;
[button setTitle:#"save" forState:UIControlStateNormal];
[self.view addSubview:button];
return button;
}
- (void)saveButtonFlyIn:(UIButton *)button {
CGRect movement = button.frame;
movement.origin.x = self.view.frame.size.width - 100;
[UIView animateWithDuration:0.2 animations:^{
button.frame = movement;
}];
}
- (void)saveButtonFlyOut:(UIButton *)button {
CGRect movement = button.frame;
movement.origin.x = self.view.frame.size.width;
[UIView animateWithDuration:0.2 animations:^{
button.frame = movement;
}];
}
#pragma mark - Save actions
- (void)saveActions {
[self saveButtonFlyOut:self.saveButton];
self.previewView.image = nil;
self.previewView.hidden = YES;
}
#end
The approach was overly complex. Where you went wrong was 1) not loading the url properly and 2) not adding the 'player layer' sublayer to the main view.
Here is an example of successful playback:
//TestURL
self.videoURL = [NSURL URLWithString:(NSString *)[self.selectedVideo objectForKey:#"source"]];
//Video
self.player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc]initWithAsset:[AVAsset assetWithURL:self.videoURL]]];
//Player layer
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height / 3);
[self.view.layer addSublayer:self.playerLayer];
[self.player play];
All you would need to do is redirect the url to the one you just saved:
self.videoURL = [self outputURL];
Edit: Here's my AppDelegate as well (part of it)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
GameViewController *gameViewController = [[GameViewController alloc]init];
NSLog(#"NSLOG %#", [[gameViewController view]class]);
_bannerViewController = [[BannerViewController alloc]initWithContentViewController:gameViewController];
self.window.rootViewController = _bannerViewController;
[self.window makeKeyAndVisible];
return YES;
}
I am about to give up. I have tried 5 different ways just these past few days to get literally one single iAd to show correctly and as simple as Apple makes it seem, literally 100% of the time I either see no ad or get an error. I have followed the Apple documentation EXACTLY.
The only clue I have is in these two lines
GameViewController *gameViewController = [[GameViewController alloc]init];
NSLog(#"NSLOG %#", [[gameViewController view]class]);
Which are in my app delegate. The NSLog gives me "UIView". No. Why? Why would that ever be a UIView, it should be an SKView, because GameViewController was pre-written for me by apple for sprite kit. How could that possibly give me the wrong object?
I am getting 'NSInvalidArgumentException', reason: '-[UIView scene]: unrecognized selector sent to instance 0x174191780' which others have recommended to fix by putting the originalContent statement but I already have that and it isn't working.
Banner view controller:
#import "BannerViewController.h"
NSString * const BannerViewActionWillBegin = #"BannerViewActionWillBegin";
NSString * const BannerViewActionDidFinish = #"BannerViewActionDidFinish";
#interface BannerViewController () <ADBannerViewDelegate>
#end
#implementation BannerViewController {
ADBannerView *_bannerView;
UIViewController *_contentController;
}
-(instancetype)initWithContentViewController:(UIViewController *)contentController{
NSAssert(contentController != nil, #"Attempting to initialize a BannerViewController with a nil contentController.");
self = [super init];
if (self != nil) {
_bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
_contentController = contentController;
_bannerView.delegate = self;
}
return self;
}
-(void)loadView{
UIView *contentView = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
//Have also tried SKView *contentView = [[SKView alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
[contentView addSubview:_bannerView];
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
self.view = contentView;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return [_contentController preferredInterfaceOrientationForPresentation];
}
-(NSUInteger)supportedInterfaceOrientations{
return [_contentController supportedInterfaceOrientations];
}
-(void)viewDidLayoutSubviews{
CGRect contentFrame = self.view.bounds, bannerFrame = CGRectZero;
bannerFrame.size = [_bannerView sizeThatFits:contentFrame.size];
if(_bannerView.bannerLoaded){
contentFrame.size.height -= bannerFrame.size.height;
bannerFrame.origin.y = contentFrame.size.height;
}else{
bannerFrame.origin.y = contentFrame.size.height;
}
_contentController.view.frame = contentFrame;
_bannerView.frame = bannerFrame;
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave{
[[NSNotificationCenter defaultCenter]postNotificationName:BannerViewActionWillBegin object:self];
return YES;
}
-(void)bannerViewActionDidFinish:(ADBannerView *)banner{
[[NSNotificationCenter defaultCenter]postNotificationName:BannerViewActionDidFinish object: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.
}
Game View controller:
#interface GameViewController ()
#property (nonatomic, strong) IBOutlet UIView *contentView;
#end
#implementation GameViewController {
}
-(instancetype)init{
self = [super init];
if (self) {
}
return self;
}
-(void)viewDidLoad{
//self.canDisplayBannerAds = YES;
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
}
-(void)viewDidLayoutSubviews{
}
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
SKView *skView = (SKView*)self.originalContentView;
if (!skView.scene) {
SKScene *scene = [GameScene sceneWithSize:skView.bounds.size];
[skView presentScene:scene];
//skView.showsPhysics = YES;
}
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskPortrait;
} else {
return UIInterfaceOrientationMaskAll;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
I figured it out. The answer, as I thought it would be, was incredibly simple and quite mind-boggling that Apple wouldn't put some sort of warning in their documentation, but then again maybe I am just too much of a noob and we are expected to know these kinds of things.
The answer, is that init was never being called in GameViewController, instead, initWithCoder: was being called. Once I NSLogged the init method and saw it wasn't being called, I figured this out.
I have created a simple hello world project for cocos2d-x 3.2. Added AdMob banner. The essence of adding banner is to create a view, then add into that view first the cocos2d-x content and then banner content:
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
[contentView addSubview:_bannerView];
self.view = contentView;
The result is that on iPhone, iPhone Retina, iPad Retina (but not in iPad) the Hello World text is distorted like this:
At the same time that stats text is not distorted:
I cannot understand what happens and why. Here is my full code:
.hfile
#import <UIKit/UIKit.h>
#interface BannerViewController : UIViewController
- (instancetype)initWithContentViewController:(UIViewController *)contentController;
- (void) hideBanner;
- (void) showBanner;
#end
and hers is .mm file
#import "BannerViewController.h"
#import "GADBannerView.h"
#interface BannerViewController () <GADBannerViewDelegate>
#end
#implementation BannerViewController {
GADBannerView *_bannerView;
UIViewController *_contentController;
Boolean _bannerLoaded;
}
- (instancetype)initWithContentViewController:(UIViewController *)contentController
{
self = [super init];
if (self != nil) {
// use kGADAdSizeBanner for a small banner in iPad
_bannerView = [[GADBannerView alloc] initWithAdSize: kGADAdSizeSmartBannerPortrait]; // scaled banner dependent on device size
_bannerView.adUnitID = #"ca-app-pub-874958723945898/8247587858";
_bannerView.delegate = self;
_contentController = contentController;
_bannerLoaded = NO;
}
return self;
}
- (void)loadView
{
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self addChildViewController:_contentController];
[contentView addSubview:_contentController.view];
[_contentController didMoveToParentViewController:self];
[contentView addSubview:_bannerView];
self.view = contentView;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [_contentController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
#endif
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [_contentController preferredInterfaceOrientationForPresentation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [_contentController supportedInterfaceOrientations];
}
// For animation
- (void)viewDidLayoutSubviews
{
CGRect contentFrame = self.view.bounds;
CGRect bannerFrame = CGRectZero;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
bannerFrame = _bannerView.frame;
#else
bannerFrame.size = [_bannerView sizeThatFits:contentFrame.size];
#endif
bannerFrame.origin.x = (contentFrame.size.width - bannerFrame.size.width) / 2;
if (_bannerLoaded) {
//contentFrame.size.height -= bannerFrame.size.height;
bannerFrame.origin.y = contentFrame.size.height - bannerFrame.size.height;
} else {
bannerFrame.origin.y = contentFrame.size.height;
}
_contentController.view.frame = contentFrame;
_bannerView.frame = bannerFrame;
}
- (void)viewDidLoad {
[super viewDidLoad];
_bannerView.rootViewController = self;
[self.view addSubview:_bannerView];
GADRequest *request = [GADRequest request];
[_bannerView loadRequest:request];
}
- (void)adViewDidReceiveAd:(GADBannerView *)bannerView
{
NSLog(#"adViewDidReceiveAd");
_bannerLoaded = YES;
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error
{
NSLog(#"adView didFailToReceiveAdWithError");
_bannerLoaded = NO;
[UIView animateWithDuration:0.25 animations:^{
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
- (void) hideBanner{
//TODO:
}
- (void) showBanner{
//TODO:
}
- (void)dealloc {
_bannerView.delegate = nil;
[_bannerView release];
[super dealloc];
}
#end
// </GADBannerViewDelegate>
And I use it in AppController.mm like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
// Init the CCEAGLView
CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]
pixelFormat: kEAGLColorFormatRGBA8
depthFormat: GL_DEPTH24_STENCIL8_OES
preserveBackbuffer: NO
sharegroup: nil
multiSampling: NO
numberOfSamples: 0];
// Use RootViewController manage CCEAGLView
_viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
_viewController.wantsFullScreenLayout = YES;
_viewController.view = eaglView;
_bannerViewController = [[BannerViewController alloc] initWithContentViewController:_viewController];
// Set RootViewController to window
if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// warning: addSubView doesn't work on iOS6
[window addSubview: _bannerViewController.view];
//[window addSubview: _viewController.view];
}
else
{
// use this method on ios6
[window setRootViewController:_bannerViewController];
// [window setRootViewController:_viewController];
}
[window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarHidden:true];
// IMPORTANT: Setting the GLView should be done after creating the RootViewController
cocos2d::GLView *glview = cocos2d::GLView::createWithEAGLView(eaglView);
cocos2d::Director::getInstance()->setOpenGLView(glview);
cocos2d::Application::getInstance()->run();
return YES;
}
What is wrong here?
I have found the problem. I appears that there is a time in hours written with black color like in the image, which on on the Hello World label and hence it distorts:
The time is shown is simulators status bar. In order to hide it I added this:
//fix not hide status on ios7
- (BOOL)prefersStatusBarHidden
{
return YES;
}
into BannerViewController class and that's it!
This is in a ModalViewController using StoryBoard and ARC
When I dismiss the view I see this line...
NSLog(#"%d %#",[imgArray count],fileName); ... being printed over and over again.
How do I kill the functions transitionWithView/animateWithDuration when the view is dismissed?
Missing something quite crucial!
.h
#import <UIKit/UIKit.h>
#interface InfoVC : UIViewController
#property (weak, nonatomic) IBOutlet UIImageView *imageview;
#property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
#end
.m
#import "InfoVC.h"
#import <QuartzCore/QuartzCore.h>
#interface InfoVC ()
#end
#implementation InfoVC {
int randomInt;
NSArray *imgs;
NSMutableArray *imgArray;
NSTimer *myTimer;
NSTimer *myTimer2;
NSString *currentImg;
}
- (void)viewDidLoad
{
[super viewDidLoad];
imgs = [NSArray arrayWithObjects:
#"01.jpg",
#"02.jpg",
#"03.jpg",
nil];
imgArray = [imgs mutableCopy];
[self initialImage];
}
- (void)initialImage
{
_imageview.contentMode = UIViewContentModeLeft;
int rnd = [imgArray count];
randomInt = (arc4random()%rnd);
currentImg = [imgArray objectAtIndex:randomInt];
UIImage *image = [UIImage imageNamed:currentImg];
[_imageview setImage:image];
_imageview.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_scrollview.contentSize = image.size;
_scrollview.contentOffset = CGPointMake(-150.0, 0.0);
[imgArray removeObjectAtIndex: randomInt];
[self animate];
}
- (void)randomImage
{
if ([imgArray count]==0) {
imgArray = [imgs mutableCopy];
}
int rnd = [imgArray count];
randomInt = (arc4random()%rnd);
NSString *fileName = [imgArray objectAtIndex:randomInt];
NSLog(#"%d %#",[imgArray count],fileName);
[imgArray removeObjectAtIndex: randomInt];
UIImage * toImage = [UIImage imageNamed:fileName];
void (^completion)(void) = ^{
[self animate];
};
[UIView transitionWithView:self.view
duration:1.75f
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction
animations:^
{
_imageview.image = toImage;
}
completion:^(BOOL finished)
{
completion();
}
];
}
- (void)animate{
CGPoint offset = _scrollview.contentOffset;
float flt = 150.0;
if (_scrollview.contentOffset.x == flt)
{
offset.x = 0.0 ;
}
else
{
offset.x = flt ;
}
void (^completion2)(void) = ^{
[self randomImage];
};
[UIView animateWithDuration:5.0 delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseIn
animations:^{
_scrollview.contentOffset = offset;
}completion:^(BOOL completed){
completion2();
}
];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[_scrollview.layer removeAllAnimations];
[_imageview.layer removeAllAnimations];
}
- (IBAction)dismissInfo:(id)sender
{
[_scrollview.layer removeAllAnimations];
[_imageview.layer removeAllAnimations];
[self dismissModalViewControllerAnimated:YES];
}
I tried using a gazillion things retro fitting transitionWithView with CABasicAnimation, using NSTimer etc.
In the end I just did:
[_imageview removeFromSuperview];
when dismissing the view and all was great.
But from other posts on here it appears there is a bug hen when applying an alpha transition to a UIScrollview - the reference to the view is lost when it's transparent.
I'm working on a soundboard app, that has several pages of buttons to play sound effects with a stop button on every page should the user wish to manually interrupt the clip. I'm using avaudioplayer in each view to play the sound upon pressing the button for that clip. It works fine until the view is changed. If a user jumps to a new page the sound keeps playing and the stop button stops working even if they return to the original view. Pressing a sound button no longer interrupts the running sound resulting in two sounds over each other.
From googling and searching this site, I know the issue is that each view change creates a new instance of the player and the remedy is to create a singleton class. Unfortunately I have yet to find any further examples of how to actually do this. If someone could provide or point the way to a beginners guide for creating an avaudioplayer singleton I would really appreciate it. All I need to be able to do is pass the file name to the shared player and start play with a sound clip button and have the stop button stop sounds no matter what view the user is on. I am using the ios 5.1 sdk with storyboards and ARC enabled.
My solution, as used in one of my own projects, is posted beneath. Feel free to copy-and-paste, I intend to open-source this project once it's finished :)
A preview of the player can be seen on YouTube: http://www.youtube.com/watch?v=Q98DQ6iNTYM
AudioPlayer.h
#protocol AudioPlayerDelegate;
#interface AudioPlayer : NSObject
#property (nonatomic, assign, readonly) BOOL isPlaying;
#property (nonatomic, assign) id <AudioPlayerDelegate> delegate;
+ (AudioPlayer *)sharedAudioPlayer;
- (void)playAudioAtURL:(NSURL *)URL;
- (void)play;
- (void)pause;
#end
#protocol AudioPlayerDelegate <NSObject>
#optional
- (void)audioPlayerDidStartPlaying;
- (void)audioPlayerDidStartBuffering;
- (void)audioPlayerDidPause;
- (void)audioPlayerDidFinishPlaying;
#end
AudioPlayer.m
// import AVPlayer.h & AVPlayerItem.h
#interface AudioPlayer ()
- (void)playerItemDidFinishPlaying:(id)sender;
#end
#implementation AudioPlayer
{
AVPlayer *player;
}
#synthesize isPlaying, delegate;
+ (AudioPlayer *)sharedAudioPlayer
{
static dispatch_once_t pred;
static AudioPlayer *sharedAudioPlayer = nil;
dispatch_once(&pred, ^
{
sharedAudioPlayer = [[self alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:sharedAudioPlayer selector:#selector(playerItemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
});
return sharedAudioPlayer;
}
- (void)playAudioAtURL:(NSURL *)URL
{
if (player)
{
[player removeObserver:self forKeyPath:#"status"];
[player pause];
}
player = [AVPlayer playerWithURL:URL];
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidStartBuffering)])
[delegate audioPlayerDidStartBuffering];
}
- (void)play
{
if (player)
{
[player play];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidStartPlaying)])
[delegate audioPlayerDidStartPlaying];
}
}
- (void)pause
{
if (player)
{
[player pause];
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidPause)])
[delegate audioPlayerDidPause];
}
}
- (BOOL)isPlaying
{
DLog(#"%f", player.rate);
return (player.rate > 0);
}
#pragma mark - AV player
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == player && [keyPath isEqualToString:#"status"])
{
if (player.status == AVPlayerStatusReadyToPlay)
{
[self play];
}
}
}
#pragma mark - Private methods
- (void)playerItemDidFinishPlaying:(id)sender
{
DLog(#"%#", sender);
if (delegate && [delegate respondsToSelector:#selector(audioPlayerDidFinishPlaying)])
[delegate audioPlayerDidFinishPlaying];
}
#end
AudioPlayerViewController.h
extern NSString *const kAudioPlayerWillShowNotification;
extern NSString *const kAudioPlayerWillHideNotification;
#interface AudioPlayerViewController : UIViewController
#property (nonatomic, assign, readonly) BOOL isPlaying;
#property (nonatomic, assign, readonly) BOOL isPlayerVisible;
- (void)playAudioAtURL:(NSURL *)URL withTitle:(NSString *)title;
- (void)pause;
#end
AudioPlayerViewController.m
NSString *const kAudioPlayerWillShowNotification = #"kAudioPlayerWillShowNotification";
NSString *const kAudioPlayerWillHideNotification = #"kAudioPlayerWillHideNotification";
#interface AudioPlayerViewController () <AudioPlayerDelegate>
#property (nonatomic, strong) AudioPlayerView *playerView;
- (void)playButtonTouched:(id)sender;
- (void)closeButtonTouched:(id)sender;
- (void)hidePlayer;
#end
#implementation AudioPlayerViewController
#synthesize playerView, isPlaying, isPlayerVisible;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
playerView = [[AudioPlayerView alloc] initWithFrame:CGRectZero];
[AudioPlayer sharedAudioPlayer].delegate = self;
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
self.view = playerView;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
[playerView.playButton addTarget:self action:#selector(playButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[playerView.closeButton addTarget:self action:#selector(closeButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Private methods
- (AudioPlayerView *)playerView
{
return (AudioPlayerView *)self.view;
}
- (void)hidePlayer
{
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillHideNotification object:nil];
[self.playerView hidePlayer];
}
- (void)playButtonTouched:(id)sender
{
DLog(#"play / pause");
if ([AudioPlayer sharedAudioPlayer].isPlaying)
{
[[AudioPlayer sharedAudioPlayer] pause];
}
else
{
[[AudioPlayer sharedAudioPlayer] play];
}
[self.playerView showPlayer];
}
- (void)closeButtonTouched:(id)sender
{
DLog(#"close");
if ([AudioPlayer sharedAudioPlayer].isPlaying)
[[AudioPlayer sharedAudioPlayer] pause];
[self hidePlayer];
}
#pragma mark - Instance methods
- (void)playAudioAtURL:(NSURL *)URL withTitle:(NSString *)title
{
playerView.titleLabel.text = title;
[[AudioPlayer sharedAudioPlayer] playAudioAtURL:URL];
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillShowNotification object:nil];
[playerView showPlayer];
}
- (void)pause
{
[[AudioPlayer sharedAudioPlayer] pause];
[[NSNotificationCenter defaultCenter] postNotificationName:kAudioPlayerWillHideNotification object:nil];
[playerView hidePlayer];
}
#pragma mark - Audio player delegate
- (void)audioPlayerDidStartPlaying
{
DLog(#"did start playing");
playerView.playButtonStyle = PlayButtonStylePause;
}
- (void)audioPlayerDidStartBuffering
{
DLog(#"did start buffering");
playerView.playButtonStyle = PlayButtonStyleActivity;
}
- (void)audioPlayerDidPause
{
DLog(#"did pause");
playerView.playButtonStyle = PlayButtonStylePlay;
}
- (void)audioPlayerDidFinishPlaying
{
[self hidePlayer];
}
#pragma mark - Properties
- (BOOL)isPlaying
{
return [AudioPlayer sharedAudioPlayer].isPlaying;
}
- (BOOL)isPlayerVisible
{
return !playerView.isPlayerHidden;
}
#end
AudioPlayerView.h
typedef enum
{
PlayButtonStylePlay = 0,
PlayButtonStylePause,
PlayButtonStyleActivity,
} PlayButtonStyle;
#interface AudioPlayerView : UIView
#property (nonatomic, strong) UIButton *playButton;
#property (nonatomic, strong) UIButton *closeButton;
#property (nonatomic, strong) UILabel *titleLabel;
#property (nonatomic, strong) UIActivityIndicatorView *activityView;
#property (nonatomic, assign) PlayButtonStyle playButtonStyle;
#property (nonatomic, assign, readonly) BOOL isPlayerHidden;
- (void)showPlayer;
- (void)hidePlayer;
#end
AudioPlayerView.m
#implementation AudioPlayerView
{
BOOL _isAnimating;
}
#synthesize playButton, closeButton, titleLabel, playButtonStyle, activityView, isPlayerHidden = _playerHidden;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"musicplayer_background.png"]];
_playerHidden = YES;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(0.0f, 0.0f, 30.0f, 30.0f);
[self addSubview:activityView];
playButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)];
[playButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_pause.png"] forState:UIControlStateNormal];
playButton.titleLabel.textAlignment = UITextAlignmentCenter;
[self addSubview:playButton];
closeButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)];
[closeButton setBackgroundImage:[UIImage imageNamed:#"button_close.png"] forState:UIControlStateNormal];
[closeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
closeButton.titleLabel.textAlignment = UITextAlignmentCenter;
[self addSubview:closeButton];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 240.0f, 30.0f)];
titleLabel.text = nil;
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.font = [UIFont boldSystemFontOfSize:13.0f];
titleLabel.numberOfLines = 2;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
[self addSubview:titleLabel];
}
return self;
}
- (void)layoutSubviews
{
#define PADDING 5.0f
DLog(#"%#", NSStringFromCGRect(self.bounds));
CGRect frame = self.bounds;
CGFloat y = frame.size.height / 2;
titleLabel.center = CGPointMake(frame.size.width / 2, y);
CGFloat x = titleLabel.frame.origin.x - (playButton.frame.size.width / 2) - PADDING;
playButton.center = CGPointMake(x, y);
activityView.center = CGPointMake(x, y);
x = titleLabel.frame.origin.x + titleLabel.frame.size.width + (closeButton.frame.size.width / 2) + PADDING;
closeButton.center = CGPointMake(x, y);
}
#pragma mark - Instance methods
- (void)showPlayer
{
if (_isAnimating || _playerHidden == NO)
return;
_isAnimating = YES;
[UIView
animateWithDuration:0.5f
animations:^
{
CGRect frame = self.frame;
frame.origin.y -= 40.0f;
self.frame = frame;
}
completion:^ (BOOL finished)
{
_isAnimating = NO;
_playerHidden = NO;
}];
}
- (void)hidePlayer
{
if (_isAnimating || _playerHidden)
return;
_isAnimating = YES;
[UIView
animateWithDuration:0.5f
animations:^
{
CGRect frame = self.frame;
frame.origin.y += 40.0f;
self.frame = frame;
}
completion:^ (BOOL finished)
{
_isAnimating = NO;
_playerHidden = YES;
}];
}
- (void)setPlayButtonStyle:(PlayButtonStyle)style
{
playButton.hidden = (style == PlayButtonStyleActivity);
activityView.hidden = (style != PlayButtonStyleActivity);
switch (style)
{
case PlayButtonStyleActivity:
{
[activityView startAnimating];
}
break;
case PlayButtonStylePause:
{
[activityView stopAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_pause.png"] forState:UIControlStateNormal];
}
break;
case PlayButtonStylePlay:
default:
{
[activityView stopAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"button_play.png"] forState:UIControlStateNormal];
}
break;
}
[self setNeedsLayout];
}
#end
AppDelegate - didFinishLaunching
// setup audio player
audioPlayer = [[AudioPlayerViewController alloc] init]; // public property ...
CGRect frame = self.window.rootViewController.view.frame;
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
CGFloat tabBarHeight = tabBarController.tabBar.frame.size.height;
audioPlayer.view.frame = CGRectMake(0.0f, frame.size.height - tabBarHeight, 320.0f, 40.0f);
[self.window.rootViewController.view insertSubview:audioPlayer.view belowSubview:tabBarController.tabBar];
From any view controller inside the app I start audio with the following code:
- (void)playAudioWithURL:(NSURL *)URL title:(NSString *)title
{
OnsNieuwsAppDelegate *appDelegate = (OnsNieuwsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.audioPlayer playAudioAtURL:URL withTitle:title];
}
Assets
For the above example, the following assets can be used (button images are white, so hard to see against background):
Buttons:
Background:
There's a lot of discussion (and links to blogs, etc.) about singletons over at What should my Objective-C singleton look like?, and I see a fair number of tutorials as a result of this Google search: http://www.google.com/search?q=+cocoa+touch+singleton+tutorial, but the real answer to your question, I believe, is that you should do one of two things:
If you do want the sound for a particular view to continue playing when the user switches, create the player as you're doing now, but when the view (re)appears, check that a player exists, and don't make a new one.
If you want the sound to stop, then stop the sound when the view changes (i.e., in viewWillDisappear:).