I have an audio player in a ViewController. I call this ViewController when a song is selected in the DidSelectRow of a tableview in another viewcontroller called the AlbumViewController.The problem I face is when i select a song ,it pushes to audioplayer view controller and starts playing ,but when i press back and select another song from the album ,the previous song is not stopped ,it still plays while the new song is selected.Now the newly selected song pushes to another instance of audio player viewcontroller and plays . Whereas the previously selected song also plays along with it . And for each selection of song ,a new instance of audio player viewcontroller is pushed ,and all the selected songs are played together. My album controller which has the tableview with it's did select row code is as below
viewContObj=[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil]; //viewcontroller=audio player controller
[self.navigationController pushViewController:viewContObj animated:YES];
viewContObj.url =[NSURL URLWithString:albumURLstring];
[viewContObj playLiveStream:nil];
and the audio player play method is as below.
-(IBAction)playLiveStream:(id)sender
{ if ( ![streamer isPlaying] )
{ [self createStreamer];
[self setButtonImageNamed:#"loadingbutton.png"];
[streamer start];
}
else
{ [self setButtonImageNamed:#"play.png"];
[streamer pause];
}}
Use singletone instance for ViewController and try like this
creating singletone instance in ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
//1. Customize singletone
-(id)initWithCustomDetails:(NSString *)customDetails
{
self = [super init];
if(_sharedMySingleton)
{
[_sharedMySingleton.view removeFromSuperview];
_sharedMySingleton = nil;
}
_sharedMySingleton = self;
return self;
}
2. exact singletone method for creating instance
+(ViewController *) getViewControllerInstance
{
#synchronized([ViewController class])
{
if (!_sharedMySingleton)
{
_sharedMySingleton = [[self alloc] init];
}
return _sharedMySingleton;
}
return nil;
}
While creating instance use
viewContObj=[[ViewController alloc]initWithCustomDetails:#"details"];
instead of this method
viewContObj=[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
//Exact singletone instance creation
viewContObj = [ViewController getViewControllerInstance];
and try..
put one ivar in .m file's #interface part like this
#property (strong, nonatomic) ViewController *playerView;
And in viewDidLoad method alloc init it as below
playerView=[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
And in tableView: didSelectRowAtIndexPath: method do as below
playerView.url =[NSURL URLWithString:albumURLstring];
[playerView playLiveStream:nil];
[self.navigationController pushViewController:playerView animated:YES];
May this solve your problem :)
Add release after pushing
viewContObj=[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
[self.navigationController pushViewController:viewContObj animated:YES];
viewContObj.url =[NSURL URLWithString:albumURLstring];
[viewContObj playLiveStream:nil];
[viewContObj release];
And in ViewController.m:
- (void)dealloc{
[streamer stop];
[streamer release];
[super dealloc];
}
Ok?
Related
I am calling the block from second class which has been declared and maintained in first class.
In ViewController.h
#property (copy) void (^simpleBlock)(NSString*);
In View Controller.m
- (void)viewDidLoad {
[super viewDidLoad];
self.simpleBlock = ^(NSString *str)
{
NSLog(#"Hello My Name is: %#",str);
};
}
In SecondViewController.m
In ViewDidload
ViewController *VC = [[ViewController alloc]init];
VC.simpleBlock(#"Harjot");//bad execution error
Please suggest me some solutions because the code is giving me bad execution error.
How can i call the block in any another way?
It's the correct way of run the block. However if you try to run a block that is nil you'll have a crash - so you should always check that it's not nil before calling it:
ViewController *vc = [[ViewController alloc] init];
if (vc.simpleClock) {
vc.simpleBlock(#"Harjot");//this will not get called
}
The reason why in your case the block is nil is because you set it in viewDidLoad - however viewDidLoad is not called until its view is ready to go on screen. For testing purposes try to move the assignment from viewDidLoad to init and this should work:
- (instancetype)init
{
self [super init];
if (self) {
_simpleBlock = ^(NSString *str)
{
NSLog(#"Hello My Name is: %#",str);
};
}
return self;
}
I have a singleton class, and I have a property declared in it:
#property (nonatomic, strong) NSString *currentTableName;
+ (SuperNoteManager*)sharedInstance;
.m file:
+ (SuperNoteManager*)sharedInstance
{
static SuperNoteManager *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[SuperNoteManager alloc] init];
});
return _sharedInstance;
}
When I run my app for the first time, there is no data in the data base,so it shows the EmptyViewController.
#property (nonatomic, strong) SuperNoteManager *myManager;
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
_myManager=[SuperNoteManager sharedInstance];
}
-(void)changeRootView{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
HomeViewController *hVC=[storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
UINavigationController *mNavVC=[storyboard instantiateViewControllerWithIdentifier:#"MainNavigationController"];
mNavVC.viewControllers=#[hVC];
[[UIApplication sharedApplication].keyWindow setRootViewController:mNavVC];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ( [_myManager checkForDataInAllTables]) {
NSLog(#"All tables are empty");
}else{
//a note is saved, show home view controller
if (![_myManager isDatabaseEmpty]) {
[self changeRootView];
}
}
}
There is + button on NavigationBar on EmptyNotesViewController, and on tap '+',
NotesViewController is pushed from EmptyNotesViewController.
In the NotesViewController, after I write some notes, I save the notes in database:
NotesViewController:
#property (nonatomic,strong) SuperNoteManager *myManager;
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
_myManager.currentTableName=#"WorkTable";
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController) {
NSLog(#"going back");
[self insertTextintoDatabase]; //Text is inserted . I double checked
}
}
And then When I go back to my EmpytNotesViewController, I check for data, and if data is present, I change the rootViewController as it is not EmptyNotesView anymore.
So When I go back to my EmptyNotesViewController:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ( [_myManager checkForDataInAllTables]) {
NSLog(#"All tables are empty");
}else{
//a note is saved, show home view controller
//Put a breakpoint here
if (![_myManager isDatabaseEmpty]) {
[self changeRootView];
}
}
}
Here at the breakpoint _myManager.currentTableName is nil. why?
I set it in the NotesController, and it became nil when it come back to the EmptyNotesController.
I thought once a value is set in singleton, it will persist as long as the app is closed/killed.
Note: I have declared the property of my Singleton class as strong and also all the properties in the singleton are declared as strong.
It appears like you never get a reference to the SuperNoteManager singleton in NotesViewController, like you did in your EmptyNotesController.
Therefore the currentTableName property never gets set in the first place.
You want to insert:
_myManager = [SuperNoteManager sharedInstance];
in your -viewDidAppear: before you set the currentTableName property.
I have an app that presents images and/or movies in sequence. The problem is, I cannot dismiss one movie player and then present another. If I try, I get the message "Warning: Attempt to present MPMoviePlayerViewController on MyViewController while a presentation is in progress!" Unlike other animated present/dismiss methods, there is no completion handler, nor a non-animated version of present/dismiss.
Here is a simplified version of my code:
-(void) play
{
[[window rootViewController] presentMoviePlayerViewControllerAnimated:player];
[[_player moviePlayer] play];
}
-(void) videoNotification:(NSNotification *) notification
{
if([notification.name isEqualToString:MPMoviePlayerPlaybackDidFinishNotification])
{
[[window rootViewController] dismissMoviePlayerViewControllerAnimated];
[_canvasManager showNextCanvas]; //this calls play on the next canvas
}
}
Any thoughts/hints on how to achieve my goal?
After looking at dismissViewControllerAnimated:completion:, I was able to create a completion handler by creating a subclass of MPMoviePlayerViewController and overriding -(void)viewDidDisappear. viewDidDisappear gets called at the end of dismissMoviePlayerViewControllerAnimated.
#interface MyMoviePlayerViewController : MPMoviePlayerViewController
{
void (^_viewDidDisappearCallback)(void);
}
- (void)setViewDidDisappearCallback:(void (^)(void))callback;
#end
#implementation MyMoviePlayerViewController
- (id) initWithContentURL:videoPath
{
self = [super initWithContentURL:videoPath];
_viewDidDisappearCallback = nil;
return self;
}
- (void)setViewDidDisappearCallback:(void (^)(void))callback
{
_viewDidDisappearCallback = [callback copy];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if(_viewDidDisappearCallback != nil)
_viewDidDisappearCallback();
}
#end
I tried to implement stripe into an iOS app through its online documentation. Everything good so far, now pushing the paymentView onto my navigation controller stack I get a completely broken screen. Thought it'd be a problem with the stripe view but when I do not log in (see code below - no identification token given) and the login screen is being pushed instead, it is completely black too. It cant be a problem with that view cause it loads just fine if I push the login view from another view before this one.
So why does pushing view via the buyButtonAction below give me black / fucked up screens?!
Ive been on this for hours.. nothing seems to work.
A pic:
the important code part:
#interface PaymentViewController ()
#end
#implementation PaymentViewController
#synthesize stripeCard = _stripeCard;
#synthesize stripeView;
#synthesize passedProductId;
- (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.
self.stripeView = [[STPView alloc] initWithFrame:CGRectMake(15,20,290,55)
andKey:#"pk_test_45mqixOu8N9S4lQ6cdn1OXBD"];
self.stripeView.delegate = self;
[self.view addSubview:self.stripeView];
}
And the call:
-(void)buyButtonAction:(id)sender
{
tokenClass *tokenObject = [tokenClass getInstance];
NSLog(#"%#", tokenObject.token);
if (tokenObject.token == nil) {
LoginController *loginController = [[LoginController alloc] init];
[self.navigationController pushViewController:loginController animated:YES];
} else {
NSLog(#"%#", tokenObject.token);
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
PaymentViewController *payView = [[PaymentViewController alloc] init];
payView.passedProductId = [[self.productData valueForKey:#"id"] objectAtIndex:hitIndex.row];
NSLog(#"passing %#", payView.passedProductId);
// push payment view
payView.navigationItem.title = #"One-Click-Payment";
[self.navigationController pushViewController:payView animated:YES];
}
}
We can see that there's a view behind the navigation bar. It's an iOS 7 related issue. Add this line to your viewDidLoad:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Or change your self.stripeView frame by adding 64 to y:
CGRectMake(15,84,290,55)
Useful link: https://stackoverflow.com/a/18103727/1835155
I am new to Core Animation and having trouble implementing a CALayer object with the drawLayer method in a delegate.
I have narrowed the problem down to a very simple test. I have a main viewController named LBViewController that pushes a secondary viewController called Level2ViewController. In the level 2 controller, in viewWillAppear:, I create a CALayer object with it's delegate=self (i.e. the level 2 controller). Whether or not I actually implement the drawLayer:inContext: method I have the same problem -- when I return to the main viewController I get a zombie crash. In the profiler it appears that the object in trouble is the level 2 viewController object -- which is being dealloc'ed after it's popped.
I've tried using a subclassed CALayer object instead of the delegate and it works fine. If I comment out the delegate assignment it also runs fine. I would like to understand why delegation is causing this problem. Any advice is greatly appreciated.
Here's my code ---
Level2ViewController
#implementation Level2ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CALayer *box1 = [[CALayer alloc] init];
box1.delegate = self; // problem disappears if I comment out this assignment
box1.backgroundColor = [UIColor redColor].CGColor;
box1.frame = CGRectMake(10,10,200,300);
[self.view.layer addSublayer:box1];
[box1 setNeedsDisplay];
}
// makes no difference whether or not this method is defined as long
// as box1.delegate == self
- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext
{
CGContextSaveGState(theContext);
CGContextSetStrokeColorWithColor(theContext, [UIColor blackColor].CGColor);
CGContextSetLineWidth(theContext, 3);
CGContextAddRect(theContext, CGRectMake(5, 5, 40, 40));
CGContextStrokePath(theContext);
CGContextRestoreGState(theContext);
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The method in LBViewController (the main controller) that pushes the level 2 view controller
- (IBAction)testAction:(id)sender {
Level2ViewController *controller = [[Level2ViewController alloc]
initWithNibName:#"Level2ViewController" bundle:nil];
controller.title = #"Level2";
// this push statement is where the profiler tells me the messaged zombie has been malloc'ed
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
You may want to set the layer's delegate to nil before the delegate object is released. So in your Leve2ViewController do this:
-(void)viewWillDisappear:(BOOL)animated
{
if (box1) {
box1.delegate = nil;
}
box1 = nil;
}
Obviously this requires, that box1 is turned into a field (so it is accessible in viewWillDisappear:)
Since you create box1in viewWillAppear: the code above uses viewWillDisappear:. Recently, when I ran into a similar problem, I had a separate delegate object in which I used init and dealloc.
Note: You call [super viewDidAppear:animated]; in viewWillAppear. Looks like a typo or copy/paste glitch :-)