I am trying to integrate SkyDrive in my iOS application and the following is the code where I have written the login authentication code. The client ID provided here is the one assigned for the application at the developer site. But the authentication always fails. Any idea what is the error ?
static NSString * const CLIENT_ID = #"00000000XXXXXXXXX";
#implementation PSMainViewController
#synthesize appLogo;
#synthesize userInfoLabel;
#synthesize signInButton;
#synthesize viewPhotosButton;
#synthesize userImage;
#synthesize liveClient;
#synthesize currentModal;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
_scopes = [NSArray arrayWithObjects:
#"wl.signin",
#"wl.basic",
#"wl.skydrive",
#"wl.offline_access", nil];
liveClient = [[LiveConnectClient alloc] initWithClientId:CLIENT_ID
scopes:_scopes
delegate:self];
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.appLogo.image = [UIImage imageNamed:#"skydrive.jpeg"];
[self updateUI];
}
- (void)viewDidUnload
{
[self setAppLogo:nil];
[self setUserInfoLabel:nil];
[self setUserImage:nil];
[self setSignInButton:nil];
[self setViewPhotosButton:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)signinButtonClicked:(id)sender {
if (self.liveClient.session == nil)
{
[self.liveClient login:self
scopes:_scopes
delegate:self];
}
else
{
[self.liveClient logoutWithDelegate:self
userState:#"logout"];
}
}
- (IBAction)viewPhotoButtonClicked:(id)sender {
// Create a Navigation controller
PSSkyPhotoViewer *aPhotoViewer = [[PSSkyPhotoViewer alloc] initWithNibName:#"PSSkyPhotoViewer" bundle:nil];
aPhotoViewer.parentVC = self;
self.currentModal = [[UINavigationController alloc] initWithRootViewController:aPhotoViewer];
[self presentModalViewController:self.currentModal animated:YES];
}
- (void) modalCompleted:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
self.currentModal = nil;
}
#pragma mark LiveAuthDelegate
- (void) updateUI {
LiveConnectSession *session = self.liveClient.session;
if (session == nil) {
[self.signInButton setTitle:#"Sign in" forState:UIControlStateNormal];
self.viewPhotosButton.hidden = YES;
self.userInfoLabel.text = #"Sign in with a Microsoft account before you can view your SkyDrive photos.";
self.userImage.image = nil;
}
else {
[self.signInButton setTitle:#"Sign out" forState:UIControlStateNormal];
self.viewPhotosButton.hidden = NO;
self.userInfoLabel.text = #"";
[self.liveClient getWithPath:#"me" delegate:self userState:#"me"];
[self.liveClient getWithPath:#"me/picture" delegate:self userState:#"me-picture"];
}
}
- (void) authCompleted: (LiveConnectSessionStatus) status
session: (LiveConnectSession *) session
userState: (id) userState {
[self updateUI];
}
- (void) authFailed: (NSError *) error
userState: (id)userState {
// Handle error here
}
#pragma mark LiveOperationDelegate
- (void) liveOperationSucceeded:(LiveOperation *)operation {
if ([operation.userState isEqual:#"me"]) {
NSDictionary *result = operation.result;
id name = [result objectForKey:#"name"];
self.userInfoLabel.text = (name != nil)? name : #"";
}
if ([operation.userState isEqual:#"me-picture"]) {
NSString *location = [operation.result objectForKey:#"location"];
if (location) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:location]];
self.userImage.image = [UIImage imageWithData:data];
}
}
}
- (void) liveOperationFailed:(NSError *)error operation:(LiveOperation *)operation
{
// Handle error here.
}
#end
May be you are not providing the redirect url in case of a desktop application.But if it's the mobile application the you have to check the "Mobile or Desktop client app: " as yes in the api settings
Related
I am integrating MoPub SDK to mediate ADs from the Google AdMob network. I can get the AD to show after implementing my own customEvent and Adapter, but i can't get the AD to handle click events on its own. As in when I click on the AdMob native AD, it won't direct me anywhere. When using Facebook and Flurry's CustomEvent and Adapter, clicks are handled automatically. Anyone have any experience on this subject?
Thanks in Advance. Code below:
MPGoogleAdMobCustomEvent
#interface MPGoogleAdMobCustomEvent()
#property(nonatomic, strong)GADAdLoader *loader;
#end
#implementation MPGoogleAdMobCustomEvent
- (void)requestAdWithCustomEventInfo:(NSDictionary *)info
{
MPLogInfo(#"MOPUB: requesting AdMob Native Ad");
NSString *adUnitID = [info objectForKey:#"adUnitID"];
if (!adUnitID) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:MPNativeAdNSErrorForInvalidAdServerResponse(#"MOPUB: No AdUnitID from GoogleAdMob")];
return;
}
self.loader = [[GADAdLoader alloc] initWithAdUnitID:adUnitID rootViewController:nil adTypes:#[kGADAdLoaderAdTypeNativeContent] options:nil];
self.loader.delegate = self;
GADRequest *request = [GADRequest request];
#if (TARGET_OS_SIMULATOR)
request.testDevices = #[ kGADSimulatorID ];
#endif
CLLocation *location = [[CLLocationManager alloc] init].location;
if (location) {
[request setLocationWithLatitude:location.coordinate.latitude
longitude:location.coordinate.longitude
accuracy:location.horizontalAccuracy];
}
request.requestAgent = #"MoPub";
[self.loader loadRequest:request];
}
- (void)adLoader:(GADAdLoader *)adLoader didReceiveNativeContentAd:(GADNativeContentAd *)nativeContentAd
{
MPLogDebug(#"MOPUB: Did receive nativeAd");
MPGoogleAdMobNativeAdAdapter *adapter = [[MPGoogleAdMobNativeAdAdapter alloc] initWithGADNativeContentAd:nativeContentAd];
adapter.url = nativeContentAd.advertiser;
MPNativeAd *interfaceAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
NSMutableArray *imageArray = [NSMutableArray array];
for (GADNativeAdImage *images in nativeContentAd.images) {
[imageArray addObject:images.imageURL];
}
[super precacheImagesWithURLs:imageArray completionBlock:^(NSArray *errors) {
if ([errors count]) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:errors[0]];
} else {
[self.delegate nativeCustomEvent:self didLoadAd:interfaceAd];
}
}];
}
- (void)adLoader:(GADAdLoader *)adLoader didFailToReceiveAdWithError:(GADRequestError *)error
{
MPLogDebug(#"MOPUB: AdMob ad failed to load with error (customEvent): %#", error.description);
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:error];
}
#end
MPGoogleAdMobNativeAdAdapter
#interface MPGoogleAdMobNativeAdAdapter()<GADNativeAdDelegate>
#property(nonatomic, strong)NSDictionary *properties;
#end
#implementation MPGoogleAdMobNativeAdAdapter
- (instancetype)initWithGADNativeContentAd:(GADNativeContentAd *)contentAD
{
self = [super init];
if (self) {
self.contentAd = contentAD;
self.contentAd.delegate = self;
self.properties = [self convertAssetsToProperties:contentAD];
}
return self;
}
- (NSDictionary *)convertAssetsToProperties:(GADNativeContentAd *)adNative
{
self.contentAd = adNative;
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
if (adNative.headline) {
dictionary[kAdTitleKey] = adNative.headline;
}
if (adNative.body) {
dictionary[kAdTextKey] = adNative.body;
}
if (adNative.images[0]) {
dictionary[kAdMainImageKey] = ((GADNativeAdImage *)adNative.images[0]).imageURL.absoluteString;
}
if (adNative.callToAction) {
dictionary[kAdCTATextKey] = adNative.callToAction;
}
return [dictionary copy];
}
#pragma mark MPNativeAdAdapter
- (NSTimeInterval)requiredSecondsForImpression
{
return 0.0;
}
- (NSURL *)defaultActionURL
{
return nil;
}
- (BOOL)enableThirdPartyClickTracking
{
return YES;
}
- (void)willAttachToView:(UIView *)view
{
self.contentAd.rootViewController = [self.delegate viewControllerForPresentingModalView];
}
- (void)didDetachFromView:(UIView *)view
{
self.contentAd.rootViewController = nil;
}
#pragma mark GADNativeAdDelegate
- (void)nativeAdWillPresentScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillPresentModalForAdapter:)]) {
[self.delegate nativeAdWillPresentModalForAdapter:self];
}
}
- (void)nativeAdDidDismissScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdDidDismissModalForAdapter:)]) {
[self.delegate nativeAdDidDismissModalForAdapter:self];
}
}
- (void)nativeAdWillLeaveApplication:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillLeaveApplicationFromAdapter:)]) {
[self.delegate nativeAdWillLeaveApplicationFromAdapter:self];
}
}
#end
`
If you are having your custom UI for AdMob Ad's, then there will be a button which you will be using for callToAction part.
First of all you need to add a selector to detect action of click, to do add the selector for that button
[callToActionButton addTarget:self action:#selector(adCalled:) forControlEvents:UIControlEventTouchUpInside];
After that implement the adCalled method to get the click & call the method further, below is the code for your reference
Below is the example which I have used to get the ad object from my collection view & then I am redirecting it.
- (void)adCalled:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:mainCollectionView]; // Get the button position
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:buttonPosition]; // Get the index path of button so that I can retrieve the correct ad object
id selectedAd = [adArray objectAtIndex:indexPath.row];
if ([selectedAd isKindOfClass:[GADNativeContentAd class]]) {
NSString *url = [selectedAd valueForKey:#"googleClickTrackingURLString"];
NSLog(#"URL is :%#", url);
NSURL *googleUrl = [NSURL URLWithString:url];
if ([[UIApplication sharedApplication] canOpenURL: googleUrl]) {
[[UIApplication sharedApplication] openURL:googleUrl];
}
}
}
Using this I can open the link n web using the google tracking url.
Hope this helps.
So in Xcode, I have a notes app that utilizes core data. There are two fields, a title textfield and a message textview. One issue I'm having is that if the user makes a note and decides to go and edit it later, the user has to edit the message to have it be able to save again. I want it to save regardless if I change the message or title. Thanks
#import "DeviceDetailViewController.h"
#interface DeviceDetailViewController ()
#end
#implementation DeviceDetailViewController
#synthesize device;
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
#synthesize message;
#synthesize titles;
#synthesize button;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[button setEnabled:NO];
titles.delegate = self;
message.delegate = (id)self;
// Do any additional setup after loading the view.
if (self.device) {
[self.titles setText:[self.device valueForKey:#"name"]];
[self.message setText:[self.device valueForKey:#"version"]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.device) {
// Update existing device
[self.device setValue:self.titles.text forKey:#"name"];
[self.device setValue:self.message.text forKey:#"version"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Device" inManagedObjectContext:context];
[newDevice setValue:self.titles.text forKey:#"name"];
[newDevice setValue:self.message.text forKey:#"version"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (titles.text.length >= 35 && range.length == 0)
return NO;
return YES;
}
//Code beyond this point is disabling keyboard when you click outside of textfield
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[message resignFirstResponder];
[titles resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[titles resignFirstResponder];
return NO;
}
//Enabling/disabling 'Save' button based on texfield data
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([titles.text length] != 0 && [message.text length] != 0) {
[button setEnabled:YES];
}
else
{
[button setEnabled:NO];
}
return YES;
}
#end
I made an AR app that recognize image and show the object recognized in an AlertView. In the AlertView I have 2 buttons: Add and Cancel, I'm using the UIAlertViewDelegate to understand which button the user pressed. If the user press the Add button, the object recognized will be stored in an array. I pass this array to another ViewController, in which I set up a TableView. On the bottom of this TableView there's a button "Pay" to go to another ViewController in which I display the total price of the object recognized. From the last ViewController I can press a button to pay the objects I selected by using the AR. Now when I press this button the app close this ViewController and go back to the first ViewController, but the array in which I stored the object that the AR recognized it's full. To delete the content of this array I thought that the best way is to use the delegation methods, so I made this:
PaymentViewController.h
#import <UIKit/UIKit.h>
#protocol PaymentViewControllerDelegate;
#interface PaymentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelTotal;
- (IBAction)buttonClosePaymentVC:(id)sender;
- (IBAction)buttonPay:(id)sender;
#property(nonatomic,strong)NSString *total;
#property(assign) id<PaymentViewControllerDelegate> delegate;
#end
#protocol PaymentViewControllerDelegate <NSObject>
- (void)cleanReportArray;
#end
PaymentViewController.m
#import "PaymentViewController.h"
#interface PaymentViewController () <UIAlertViewDelegate>
#end
#implementation PaymentViewController
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.labelTotal.text = self.total;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClosePaymentVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonPay:(id)sender {
NSString *pay = [NSString stringWithFormat:#"Stai per pagare %#, procedi?", self.total];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:pay delegate:self cancelButtonTitle:#"Si" otherButtonTitles:#"No", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// Procedura per il pagamento e cancellazione del file plist
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"objects.plist"];
NSError *error;
if (![[NSFileManager defaultManager]removeItemAtPath:path error:&error]) {
NSLog(#"Errore: %#", error);
}
__weak UIViewController *vcThatPresentedCurrent = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[vcThatPresentedCurrent dismissViewControllerAnimated:YES completion:nil];
}];
[self.delegate cleanReportArray];
}
if (buttonIndex == 1) {
// Non deve far nulla: fa scomparire l'UIAlertView
}
}
Here I post to you the method of the class that will use the delegate:
Interface of the ScannerViewController.m
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
In ViewDidLoad I inserted this rows:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
And in the ScannerViewController.m I implemented the method I declared in PaymentViewController.h:
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
I tested my app on my iPhone, the app works fine until I try to pay the objects I scanned by camera, indeed, I tried to pay the object, but it doesn't clean the array in which I stored the objects scanned.
What's wrong in my code? I used an tutorial on the web to understand better how the delegation method works. I hope you can help me to fix this issue, thank you
UPDATE:
here i will post my ScannerViewController code:
ScannerViewController.h
#import <UIKit/UIKit.h>
#interface ScannerViewController : UIViewController
#end
ScannerViewController.m
#import "ScannerViewController.h"
#import "PaymentViewController.h"
#import "ReportViewController.h"
#import "MSScannerSession.h"
#import "MSResult.h"
#import "XmlReader.h"
static int kMSScanOptions = MS_RESULT_TYPE_IMAGE |
MS_RESULT_TYPE_EAN8 |
MS_RESULT_TYPE_EAN13;
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
#implementation ScannerViewController {
MSScannerSession *_scannerSession;
NSString *nameOfObjectScanned;
XmlReader *reader;
NSMutableArray *arrayObjectAdded;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_scannerSession = [[MSScannerSession alloc] initWithScanner:[MSScanner sharedInstance]];
[_scannerSession setScanOptions:kMSScanOptions];
[_scannerSession setDelegate:self];
}
return self;
}
- (void)session:(MSScannerSession *)scanner didScan:(MSResult *)result {
if (!result) {
return;
}
[_scannerSession pause];
NSString *resultStr = nil;
if (result) {
switch ([result getType]) {
case MS_RESULT_TYPE_IMAGE:
resultStr = [NSString stringWithFormat:#"Immagine trovata: %#", [result getValue]];
break;
case MS_RESULT_TYPE_EAN8:
case MS_RESULT_TYPE_EAN13:
resultStr = [NSString stringWithFormat:#"EAN trovato: %#", [result getValue]];
break;
default:
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *asView = [[UIActionSheet alloc]initWithTitle:resultStr delegate:self cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
asView.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[asView showInView:self.view];
[self addObjectToList:resultStr];
});
}
- (void)addObjectToList:(NSString *)objectName {
// Ricerca dell'oggetto
NSString *object = [objectName substringFromIndex:18];
if ([object isEqualToString:#"Binario_con_coppia"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_colorati"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_rossi"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Bici_da_corsa"]) {
[self showAlert:object];
}
}
- (void)showAlert:(NSString*)name {
name = [name stringByReplacingOccurrencesOfString:#"_" withString:#" "];
nameOfObjectScanned = name;
NSString *message = [NSString stringWithFormat:#"Ho riconosciuto questo oggetto: %#, vuoi aggiungerlo al carrello?", name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:message delegate:self cancelButtonTitle:#"Aggiungi" otherButtonTitles:#"Annulla", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Aggiungi");
for (int i = 0; i < [reader.objArray count]; i++) {
if ([[reader.objArray[i]objectForKey:#"name"] isEqualToString:nameOfObjectScanned]) {
// Salvo il nome dell'oggetto trovato, il prezzo e la descrizione
NSString *name = [reader.objArray[i]objectForKey:#"name"];
NSString *desc = [reader.objArray[i]objectForKey:#"desc"];
NSString *price = [reader.objArray[i]objectForKey:#"price"];
NSDictionary *newObjectAdded = [[NSDictionary alloc]init];
newObjectAdded = #{#"name": name,
#"desc": desc,
#"price": price};
[arrayObjectAdded addObject:newObjectAdded];
}
}
} else {
NSLog(#"Annulla");
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[_scannerSession resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
arrayObjectAdded = [[NSMutableArray alloc]init];
CALayer *videoPreviewLayer = [self.videoPreview layer];
[videoPreviewLayer setMasksToBounds:YES];
CALayer *captureLayer = [_scannerSession previewLayer];
[captureLayer setFrame:[self.videoPreview bounds]];
[videoPreviewLayer insertSublayer:captureLayer below:[[videoPreviewLayer sublayers] objectAtIndex:0]];
reader = [[XmlReader alloc]init];
[reader parseXml];
[_scannerSession startCapture];
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
}
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
- (void)dealloc {
[_scannerSession stopCapture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)stopScanner:(id)sender {
ReportViewController *reportVC = [[ReportViewController alloc]initWithNibName:#"ReportViewController" bundle:nil];
reportVC.reportArray = arrayObjectAdded;
[reportVC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:reportVC animated:YES completion:nil];
}
#end
To recognize picture I'm using this AR SDK. I hope you can help me to understand where's my issue
Your problem is that in viewDidLoad you have the code:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
this is the last thing you do in that method. So the instance of PaymentViewController that you create and set the delegate on is immediately destroyed (by ARC).
You need to modify your code so that you call setDelegate: on the actual instance of PaymentViewController that is presented on screen as this is the instance that needs to use the delegate (it receives the callback from the alert view).
I'm struggling for couple of days now to sort this thing out and simply just can't find the way. I want to play audio in background when app exits or when i click on link to go to Safari, but i just wont go to background mode. Please help.
FirstViewController.h file :
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>
#import <AVFoundation/AVFoundation.h>
#interface RygestopFirstViewController : UIViewController <AVAudioPlayerDelegate> {
IBOutlet UIButton *playButton;
IBOutlet UISlider *volumeSlider;
IBOutlet UISlider *progressBar;
IBOutlet UILabel *currentTime;
IBOutlet UILabel *duration;
AVAudioPlayer *player;
UIImage *playBtnBG;
UIImage *pauseBtnBG;
NSTimer *updateTimer;
BOOL inBackground;
}
- (IBAction)playButtonPressed:(UIButton*)sender;
- (IBAction)volumeSliderMoved:(UISlider*)sender;
- (IBAction)progressSliderMoved:(UISlider*)sender;
#property (nonatomic, retain) UIButton *playButton;
#property (nonatomic, retain) UISlider *volumeSlider;
#property (nonatomic, retain) UISlider *progressBar;
#property (nonatomic, retain) UILabel *currentTime;
#property (nonatomic, retain) UILabel *duration;
#property (nonatomic, retain) NSTimer *updateTimer;
#property (nonatomic, assign) AVAudioPlayer *player;
#property (nonatomic, assign) BOOL inBackground;
#end
FirstViewController.m code:
// amount to skip on rewind or fast forward
#define SKIP_TIME 1.0
// amount to play between skips
#define SKIP_INTERVAL .2
#implementation RygestopFirstViewController
#synthesize playButton;
#synthesize volumeSlider;
#synthesize progressBar;
#synthesize currentTime;
#synthesize duration;
#synthesize updateTimer;
#synthesize player;
#synthesize inBackground;
-(void)updateCurrentTimeForPlayer:(AVAudioPlayer *)p
{
currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)p.currentTime / 60, (int)p.currentTime % 60, nil];
progressBar.value = p.currentTime;
}
- (void)updateCurrentTime
{
[self updateCurrentTimeForPlayer:self.player];
}
- (void)updateViewForPlayerState:(AVAudioPlayer *)p
{
[self updateCurrentTimeForPlayer:p];
if (updateTimer)
[updateTimer invalidate];
if (p.playing)
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(updateCurrentTime) userInfo:p repeats:YES];
}
else
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
updateTimer = nil;
}
}
- (void)updateViewForPlayerStateInBackground:(AVAudioPlayer *)p
{
[self updateCurrentTimeForPlayer:p];
if (p.playing)
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
else
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
}
-(void)updateViewForPlayerInfo:(AVAudioPlayer*)p
{
duration.text = [NSString stringWithFormat:#"%d:%02d", (int)p.duration / 60, (int)p.duration % 60, nil];
progressBar.maximumValue = p.duration;
volumeSlider.value = p.volume;
}
-(void)pausePlaybackForPlayer:(AVAudioPlayer*)p
{
[p pause];
[self updateViewForPlayerState:p];
}
-(void)startPlaybackForPlayer:(AVAudioPlayer*)p
{
if ([p play])
{
[self updateViewForPlayerState:p];
}
else
NSLog(#"Could not play %#\n", p.url);
}
- (IBAction)playButtonPressed:(UIButton *)sender
{
if (player.playing == YES)
[self pausePlaybackForPlayer: player];
else
[self startPlaybackForPlayer: player];
}
- (IBAction)volumeSliderMoved:(UISlider *)sender
{
player.volume = [sender value];
}
- (IBAction)progressSliderMoved:(UISlider *)sender
{
player.currentTime = sender.value;
[self updateCurrentTimeForPlayer:player];
}
- (void)dealloc
{
[super dealloc];
[playButton release];
[volumeSlider release];
[progressBar release];
[currentTime release];
[duration release];
[updateTimer release];
[player release];
[playBtnBG release];
[pauseBtnBG release];
}
#pragma mark AVAudioPlayer delegate methods
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag
{
if (flag == NO)
NSLog(#"Playback finished unsuccessfully");
[p setCurrentTime:0.];
if (inBackground)
{
[self updateViewForPlayerStateInBackground:p];
}
else
{
[self updateViewForPlayerState:p];
}
}
- (void)playerDecodeErrorDidOccur:(AVAudioPlayer *)p error:(NSError *)error
{
NSLog(#"ERROR IN DECODE: %#\n", error);
}
// we will only get these notifications if playback was interrupted
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)p
{
NSLog(#"Interruption begin. Updating UI for new state");
// the object has already been paused, we just need to update UI
if (inBackground)
{
[self updateViewForPlayerStateInBackground:p];
}
else
{
[self updateViewForPlayerState:p];
}
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)p
{
NSLog(#"Interruption ended. Resuming playback");
[self startPlaybackForPlayer:p];
}
#pragma mark background notifications
- (void)registerForBackgroundNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(setInBackgroundFlag)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(clearInBackgroundFlag)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)setInBackgroundFlag
{
inBackground = true;
}
- (void)clearInBackgroundFlag
{
inBackground = false;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Play", #"First");
self.tabBarItem.image = [UIImage imageNamed:#"Home"];
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
return YES;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
playBtnBG = [[UIImage imageNamed:#"Player.png"] retain];
pauseBtnBG = [[UIImage imageNamed:#"Pause.png"] retain];
[playButton setImage:playBtnBG forState:UIControlStateNormal];
[self registerForBackgroundNotifications];
updateTimer = nil;
duration.adjustsFontSizeToFitWidth = YES;
currentTime.adjustsFontSizeToFitWidth = YES;
progressBar.minimumValue = 0.0;
// Load the the sample file, use mono or stero sample
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"Sound1" ofType:#"m4a"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self.player)
{
[self updateViewForPlayerInfo:player];
[self updateViewForPlayerState:player];
player.numberOfLoops = 0;
player.delegate = self;
}
[fileURL release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
And, by the way, i want to run thin in tab bar application, so the background mode must be present always.
Here's what you're looking for: https://devforums.apple.com/message/264397 and set your background mode to 'App plays audio' in your app's .plist file.
I have a problem. In my program I need to cancel operations (subclass NSOperation) in queue after clicking on button. But when I calling [queue cancelAllOperations] nothing happens. The queue continue executing. All operations must be concurrent. What am I doing wrong?
#interface SearchOperation : NSOperation
{
TrueSearcherViewController *viewController;
SearchYouTube *you_search;
SearchGoogle *goo_search;
BOOL semafore;
}
- (id)initYoutubeTaskWithData:(SearchYouTube *) sy;
- (id)initGoogleTaskWithData:(SearchGoogle *) sg;
- (void) beginYoutubeSearch:(SearchYouTube *) sy;
- (void) beginGoogleSearch:(SearchGoogle *) sg;
#end
#import "SearchOperation.h"
#implementation SearchOperation
- (void) start
{
if (semafore == YES)
{
[self beginYoutubeSearch:you_search];
}
else
{
[self beginGoogleSearch:goo_search];
}
}
- (id)initYoutubeTaskWithData:(SearchYouTube *) sy
{
if (self = [super init])
{
you_search = sy;
semafore = YES;
}
return self;
}
- (id)initGoogleTaskWithData:(SearchGoogle *) sg
{
if (self = [super init])
{
goo_search = sg;
semafore = NO;
}
return self;
}
- (void) beginYoutubeSearch:(SearchYouTube *) sy
{
[sy runSearch];
}
- (void) beginGoogleSearch:(SearchGoogle *) sg
{
[sg runSearch];
}
- (void) dealloc
{
[super dealloc];
}
#end
You need to check in your code if your operation is cancelled to interrupt it with :
if(self.isCancelled){
return;
}