download multiple images with ASIHttpRequest - objective-c

I have a UITableView which contain several cell. When I click a cell, I push an other controller which shows the detail of this cell. In the detail I have a scrollView which contains several UIImageViews. I would like to download the images for these views from the web using ASIHTTPRequest, when the detail view is loaded.

You can override UIView. Each view has an ASIHTTPRequest. When each download has finished, you can use drawRect to draw the downloaded image.
this is a demo:
MyImageView.h
#import <UIKit/UIKit.h>
#import "ASIHTTPRequest.h"
#interface MyImageView : UIView <ASIHTTPRequestDelegate>
{
ASIHTTPRequest *httpRequest;
UIImage *image;
}
- (void)startRequest:(NSString *)_url;
#end
MyImageView.m
#import "MyImageView.h"
#implementation MyImageView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
// Drawing code
if (image != nil) {
[image drawInRect:self.bounds];
}
}
- (void)dealloc
{
[httpRequest clearDelegatesAndCancel];
[httpRequest release];
[image release];
[super dealloc];
}
-(void)startRequest:(NSString *)_url
{
if (httpRequest != nil) {
[httpRequest clearDelegatesAndCancel];
[httpRequest release];
}
httpRequest = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:_url]];
[httpRequest setTimeOutSeconds:30];
[httpRequest setDelegate:self];
[httpRequest startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
if ([request responseStatusCode] == 200) {
image = [[UIImage alloc] initWithData:[request responseData]];
[self setNeedsDisplay];
}
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"request failed");
}
Usage:
MyImageView *imageView = [[MyImageView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
[imageView startRequest:#"http://imageUrl"];
[self.view addSubview:imageView];
[imageView release];

Here's a class derived from UIImageView:
Header file, UIHTTPImageView.h:
#import "ASIHTTPRequest.h"
#interface UIHTTPImageView : UIImageView {
ASIHTTPRequest *request;
}
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
#end
and UIHTTPImageView.m:
#import "UIHTTPImageView.h"
#implementation UIHTTPImageView
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder {
[request setDelegate:nil];
[request cancel];
[request release];
request = [[ASIHTTPRequest requestWithURL:url] retain];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
if (placeholder)
self.image = placeholder;
[request setDelegate:self];
[request startAsynchronous];
}
- (void)dealloc {
[request setDelegate:nil];
[request cancel];
[request release];
[super dealloc];
}
- (void)requestFinished:(ASIHTTPRequest *)req
{
if (request.responseStatusCode != 200)
return;
self.image = [UIImage imageWithData:request.responseData];
}
#end
Note that there's no reporting of errors, you may want an requestFailed: method if you want to report a problem to the user.

Related

How to login With instagram and share wtih instagram Using IOS ? Objective c

1) Register to Instagram
To create Application using the Instagram API, you must have an account with Instagram.
After creating your account in Instagram, login with Instagram account and open the URL: http://instagram.com/developer/
Go to “Register your application” and click on the “Register New Client” button.
You will be asked to provide Application Name, Description of your application, website and oAuth redirect_url. Here, the oAuth redirect_url specifies where to redirect users after they have chosen whether or not to authenticate your application.
After successfully registering new client, Instagram will provide CLIENT INFO like CLIENT ID, CLIENT SECRET, WEBSITE URL, REDIRECT URI. Save CLIENT ID,CLIENT SECRET, REDIRECT URI to your application constants class as you will need this for authenticating to Instagram.
Lets see how can we authenticate…
Step 1.
At First set the authentication URL
Create a header file and provide the header file name is ConstantHandle
and set the all authentication URL
#ifndef ConstantHandler_h
#define ConstantHandler_h
//set User authentication and url
#define INSTAGRAM_AUTHURL #"https://api.instagram.com/oauth/authorize/"
#define INSTAGRAM_APIURl #"https://api.instagram.com/v1/users/"
#define INSTAGRAM_CLIENT_ID #"Client Id"
#define INSTAGRAM_CLIENTSERCRET #"Clients Secret"
#define INSTAGRAM_REDIRECT_URL #"Redirect URL"
#define INSTAGRAM_ACCESS_TOKEN #"access_token"
#define INSTAGRAM_SCOPE   #"likes+comments+relationships+basic"
//Contant Url
#define ACCESS_TOKEN #"#access_token="
#define UNSIGNED #"UNSIGNED"
#define CODE #"code="
#define END_POINT_URL #"https://api.instagram.com/oauth/access_token"
#define HTTP_METHOD #"POST"
#define CONTENT_LENGTH #"Content-Length"
#define REQUEST_DATA #"application/x-www-form-urlencoded"
#define CONTENT_TYPE #"Content-Type"
//share Photo Constant
#define DOCUMENT_FILE_PATH #"Documents/originalImage.ig"
#define APP_URL #"instagram://app"
#define UTI_URL #"com.instagram.exclusivegram"
#define MESSAGE #"Instagram not installed in this device!\nTo share image please install instagram."
#endif /* ConstantHandler_h */
At first set the all micro
Step 2.
Add a file in your project
Provide the file name is
InstagramController
create a file inherit with UIViewController
Add the this code in InstagramController.h file
#import <UIKit/UIKit.h>
#import "ConstantHandler.h"
#interface InstagramController : UIViewController
- (void)loginWithInstagramWithParsentViewController:(UIViewController *)controller completionHandler:(void(^)(NSDictionary *userProfileInformation))completionHanlder failureHandler:(void(^)(NSDictionary *errorDetail))failureHandler;
- (void)sharePhotoWithInstagaramWithImage:(UIImage *)image parsentViewcontroller:(UIViewController *)controller;;
#end
Add the this code in InstagramController.m file
#import "InstagramController.h"
#interface InstagramController ()<UIWebViewDelegate,UIDocumentInteractionControllerDelegate>
{
UIView *_progressView;
UIWebView *_webView;
UIViewController *_controller;
UIActivityIndicatorView *_activitiyIndicator;
}
#property(strong,nonatomic)NSString *typeOfAuthentication;
#property (nonatomic, strong) void(^completionHandler)(NSDictionary *);
#property (nonatomic, strong) void(^failureHandler)(NSDictionary *);
#property(nonatomic,strong)UIDocumentInteractionController *docFile;
#end
#pragma mark - View Controller Life Cycle Method
#implementation InstagramController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewWillAppear:(BOOL)animated {
//Add the cancel Button
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(10, 30, 70, 20)];
[button setTitle:#"Cancel" forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[button addTarget:self action:#selector(cancel:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
//Setup The UIWebView
[super viewDidAppear: animated];
_webView = [UIWebView new];
CGRect frame = self.view.frame;
frame.origin.y = 64;
_webView.frame = frame;
_webView.delegate = self;
[self.view addSubview:_webView];
//Hit instagaram API;
NSString* authURL = nil;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
[[NSUserDefaults standardUserDefaults] synchronize];
if ([_typeOfAuthentication isEqualToString:UNSIGNED])
{
authURL = [NSString stringWithFormat: #"%#?client_id=%#&redirect_uri=%#&response_type=token&scope=%#&DEBUG=True",
INSTAGRAM_AUTHURL,
INSTAGRAM_CLIENT_ID,
INSTAGRAM_REDIRECT_URL,
INSTAGRAM_SCOPE];
}
else
{
authURL = [NSString stringWithFormat: #"%#?client_id=%#&redirect_uri=%#&response_type=code&scope=%#&DEBUG=True",
INSTAGRAM_AUTHURL,
INSTAGRAM_CLIENT_ID,
INSTAGRAM_REDIRECT_URL,
INSTAGRAM_SCOPE];
}
[_webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: authURL]]];
}
#pragma mark - Local Method
/*!
Setup The genral Indicator View
#retur void
*/
- (void)addIndicatorView {
_progressView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 62)];
_progressView.layer.cornerRadius = 10;
_progressView.layer.masksToBounds = YES;
_progressView.backgroundColor = [UIColor blackColor];
_progressView.alpha = 0.7;
UILabel *lable = [[UILabel alloc]initWithFrame:CGRectMake(10,43, 80, 15)];
lable.textColor = [UIColor grayColor];
[lable setTextAlignment:NSTextAlignmentCenter];
lable.font = [UIFont italicSystemFontOfSize:15.0f];
lable.text = #"progress...";
[_progressView addSubview:lable];
_activitiyIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[_activitiyIndicator setCenter:CGPointMake(_progressView.frame.size.width/2.0, _progressView.frame.size.height/2.3)]; // I do this because I'm in landscape mode
[_progressView addSubview:_activitiyIndicator];
[_activitiyIndicator startAnimating];
_progressView.center = self.view.center;
[_webView addSubview:_progressView];
}
/*!
This method is used to request to call back Url and check the authenTication
#param NSURLRequest is the check the request URl;
#return BOOLk
*/
- (BOOL) checkRequestForCallbackURL: (NSURLRequest*) request
{
NSString* urlString = [[request URL] absoluteString];
if ([_typeOfAuthentication isEqualToString:UNSIGNED])
{
// check, if auth was succesfull (check for redirect URL)
if([urlString hasPrefix: INSTAGRAM_REDIRECT_URL])
{
// extract and handle access token
NSRange range = [urlString rangeOfString: ACCESS_TOKEN ];
[self handleAuth:[urlString substringFromIndex: range.location+range.length] withProfileInfo:nil];
return NO;
}
}
else
{
if([urlString hasPrefix: INSTAGRAM_REDIRECT_URL])
{
// extract and handle code
NSRange range = [urlString rangeOfString: CODE];
[self makePostRequest:[urlString substringFromIndex: range.location+range.length]];
return NO;
}
}
return YES;
}
/*!
This method is used to get the User profile information
#param NSString is a authToken
#return void;
*/
-(void)makePostRequest:(NSString *)authToken
{
NSString *post = [NSString stringWithFormat:#"client_id=%#&client_secret=%#&grant_type=authorization_code&redirect_uri=%#&code=%#",INSTAGRAM_CLIENT_ID,INSTAGRAM_CLIENTSERCRET,INSTAGRAM_REDIRECT_URL,authToken];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[postData length]];
// URL of the endpoint we're going to contact.
NSURL *url = [NSURL URLWithString:END_POINT_URL];
// Create a POST request with our JSON as a request body.
NSMutableURLRequest *requestData = [NSMutableURLRequest requestWithURL:url];
requestData.HTTPMethod = HTTP_METHOD;
[requestData setValue:postLength forHTTPHeaderField:CONTENT_LENGTH];
[requestData setValue:REQUEST_DATA forHTTPHeaderField:CONTENT_TYPE];
requestData.HTTPBody = postData;
// Create a task.
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:requestData
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error)
{
if (!error)
{
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
[self handleAuth:[dictionary valueForKey:#"access_token"] withProfileInfo:dictionary];
} else{
NSLog(#"Error: %#", error.localizedDescription);
[self handleAuth:nil withProfileInfo:nil];
}
}];
// Start the task.
[task resume];
}
/*!
This method is used to get The profile information is the request is completed
#param NSSTring authetication key
#return void
*/
- (void) handleAuth: (NSString*)authToken withProfileInfo:(NSDictionary *)dictionary
{
NSLog(#"successfully logged in with Tocken == %#",authToken);
if (dictionary) {
_completionHandler(dictionary);
} else _failureHandler(dictionary);
// [self makePostRequest:authToken];
[self cancelLogin];
}
- (void)cancelLogin {
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *vc = [_controller.childViewControllers lastObject];
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
});
}
#pragma mark -WebView Delegate Method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
return [self checkRequestForCallbackURL: request];
}
- (void) webViewDidStartLoad:(UIWebView *)webView
{
[self addIndicatorView];
}
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
[_progressView removeFromSuperview];
_progressView = nil;
[_activitiyIndicator stopAnimating];
}
- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[self webViewDidFinishLoad: webView];
}
#pragma mark - user Define Method
- (void)loginWithInstagramWithParsentViewController:(UIViewController *)controller completionHandler:(void(^)(NSDictionary *userProfileInformation))completionHanlder failureHandler:(void(^)(NSDictionary *errorDetail))failureHandler {
_controller = controller;
[controller addChildViewController:self];
self.view.frame = controller.view.frame;
[controller.view addSubview:self.view];
[self didMoveToParentViewController:controller];
_completionHandler = completionHanlder;
_failureHandler = failureHandler;
}
- (void)sharePhotoWithInstagaramWithImage:(UIImage *)image parsentViewcontroller:(UIViewController *)controller{
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:DOCUMENT_FILE_PATH];
if ([[NSFileManager defaultManager] fileExistsAtPath:savePath]) {
NSFileManager *fielManager = [NSFileManager defaultManager];
[fielManager removeItemAtPath:savePath error:nil];
}
BOOL save = [UIImagePNGRepresentation(image) writeToFile:savePath atomically:YES];
NSURL *instagramURL = [NSURL URLWithString:APP_URL];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL] && save) {
self.docFile = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:savePath]];
self.docFile.UTI = UTI_URL;
self.docFile.delegate = self;
[self.docFile presentOpenInMenuFromRect:CGRectZero inView:controller.view animated:YES];
} else {
NSLog(#"%#",MESSAGE);
}
}
#pragma mark - UIDocumentInteractionController delegateMethod
- (UIDocumentInteractionController *) setupControllerWithURL: (NSURL*) fileURL usingDelegate: (id <UIDocumentInteractionControllerDelegate>) interactionDelegate {
UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL: fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
#pragma mark - selector method
-(void)cancel:(UIButton *)button {
[self cancelLogin];
}
#end
Step 3:
Finally import "ConstantHandler.h" file in ViewController
Add the Login and share Button in ViewController and the this code
#import "ViewController.h"
#import "InstagramController.h"
#interface ViewController ()
#property(nonatomic,strong) InstagramController *instagramHandler ;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)loginWithInstagram:(id)sender {
_instagramHandler = [InstagramController new];
[_instagramHandler loginWithInstagramWithParsentViewController:self completionHandler:^(NSDictionary *userProfileInformation) {
NSLog(#"%#",userProfileInformation);
} failureHandler:^(NSDictionary *errorDetail) {
NSLog(#"%#",errorDetail);
}];
}
- (IBAction)shareWithInstagram:(id)sender {
_instagramHandler = [InstagramController new];
UIImage *image = [UIImage imageNamed:#"flower-197343_960_720.jpg"];
[_instagramHandler sharePhotoWithInstagaramWithImage:image parsentViewcontroller:self];
}
#end
Step 4.
Build and run the project
Delete NSHTTPCookieStorage and Use App Transport Security.
And add webView delegate before webView request. After use method, dealloc and set webView delegate to nil.

Page View Controller: UILabel and UIImageview empty on first page

I'm using a UIPageViewController to display items from a JSON file. It works fine except for the first page which displays nothing on loading, but if I come back, it works.
Code is as follows:
#import "SJPagesViewController.h"
#import "SJChildViewController.h"
#interface SJPagesViewController ()
#end
#implementation SJPagesViewController
#synthesize urlToFollow, data,articlesArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
...
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
CGFloat window_height = ([self window_height]-30.0);
CGFloat window_width = [self window_width];
CGRect pageFrame = CGRectMake(0.0f, 0.0f,window_width , window_height);
self.pageController.dataSource = self;
[[self.pageController view] setFrame:pageFrame];
SJChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
//Download JSON
NSError *error=nil;
NSURL *url = [NSURL URLWithString:urlToFollow];
data = [NSData dataWithContentsOfURL: url options:NSDataReadingMappedIfSafe error:&error];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSArray *response = [dictionary objectForKey:#"items"];
articlesArray = [[NSArray alloc] initWithArray:response];
//NSLog(#"articlesArray = %#", articlesArray);
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger index = [(SJChildViewController *)viewController index];
if (index == 0) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(SJChildViewController *)viewController index];
index++;
if (index == articlesArray.count) {
return nil;
}
return [self viewControllerAtIndex:index];
}
- (CGFloat) window_height {
return [UIScreen mainScreen].applicationFrame.size.height;
}
- (CGFloat) window_width {
return [UIScreen mainScreen].applicationFrame.size.width;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (SJChildViewController *)viewControllerAtIndex:(NSUInteger)index {
SJChildViewController *childViewController = [[SJChildViewController alloc] initWithNibName:#"SJChildViewController" bundle:nil];
childViewController.index = index;
childViewController.arrayCount = self.articlesArray.count;
childViewController.model = [[self.articlesArray objectAtIndex:index]objectForKey:#"modelo"];
childViewController.price = [[self.articlesArray objectAtIndex:index]objectForKey:#"precio"];
childViewController.make = [[self.articlesArray objectAtIndex:index]objectForKey:#"marca"];
childViewController.imageUrl = [[self.articlesArray objectAtIndex:index]objectForKey:#"photoUrl"];
return childViewController;
}
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController {
// The number of items reflected in the page indicator.
if (articlesArray.count >5) {
return 5;
}else return [articlesArray count];
}
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController {
// The selected item reflected in the page indicator.
return 0;
}
#end
And ChildViewController to display items:
#implementation SJChildViewController
#synthesize activityIndicator,imageUrl,price,model,make;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
....
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Activity indicator
activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0);
[self.view addSubview: activityIndicator];
[activityIndicator startAnimating];
}
-(void)viewDidAppear:(BOOL)animated{
self.scrrenNumber.text = [NSString stringWithFormat:#"Artículo %ld de %ld", ((long)self.index+1), (long)self.arrayCount];
self.lblMake.lineBreakMode = NSLineBreakByWordWrapping;
self.lblMake.text = [NSString stringWithFormat:#"%#",make];
//Donload image
//Download image from url
NSURL *url_1= [NSURL URLWithString:imageUrl];
NSURLRequest *request_1 = [NSURLRequest requestWithURL:url_1];
[NSURLConnection sendAsynchronousRequest:request_1
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
UIImage *img = [UIImage imageWithData:data];
[self.articleImage performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
}];
//Activity indicator
self.lblPrice.text = [NSString stringWithFormat:#"%#",price];
self.lblModel.lineBreakMode = NSLineBreakByWordWrapping;
self.lblModel.text = [NSString stringWithFormat:#"%#",model];
[activityIndicator stopAnimating];
}
How can I make it work from the first moment?
Luis, I don't have access to xcode right now but it appears your issue is that you are instantiating childViewController while articlesArray is empty.
In viewDidLoad you are downloading your json file and populating articlesArray after you call your helper method viewControllerAtIndex.
Try downloading your json file and populating the array first like you have here.
//Download JSON
NSError *error=nil;
NSURL *url = [NSURL URLWithString:urlToFollow];
data = [NSData dataWithContentsOfURL: url options:NSDataReadingMappedIfSafe error:&error];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSArray *response = [dictionary objectForKey:#"items"];
articlesArray = [[NSArray alloc] initWithArray:response];
Then create your pageViewController and populate it like you did here.
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
CGFloat window_height = ([self window_height]-30.0);
CGFloat window_width = [self window_width];
CGRect pageFrame = CGRectMake(0.0f, 0.0f,window_width , window_height);
self.pageController.dataSource = self;
[[self.pageController view] setFrame:pageFrame];
SJChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];

Correctly Stoping AVAudioPlayer. Currently runs in Background

I've been strugling with this problem for quite a while.
I'm trying to make a player that contains a playlist and plays only the music files stored inside the application.
Now, i'm using AVAudioPlayer to play the mp3 files. My problem is that when i load the playlist i can't stop the previous mp3 from playing and therefor i get a mixture of sounds between the first audio and all the other audio files that i load from the playlist.
so, here is my code:
#import "MainViewController.h"
#import <Foundation/Foundation.h>
#pragma mark Audio session callbacks_______________________
#implementation MainViewController
#synthesize artworkItem;
#synthesize userMediaItemCollection;
#synthesize playBarButton;
#synthesize pauseBarButton;
#synthesize musicPlayer;
#synthesize navigationBar;
#synthesize noArtworkImage;
#synthesize backgroundColorTimer;
#synthesize nowPlayingLabel, AudFile;
#synthesize appSoundButton;
#synthesize addOrShowMusicButton;
#synthesize appSoundPlayer;
#synthesize soundFileURL;
#synthesize interruptedOnPlayback;
#synthesize playedMusicOnce;
#synthesize playing;
#pragma mark Music control________________________________
- (IBAction) playOrPauseMusic: (id)sender {
}
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
#pragma mark Application playback control_________________
- (IBAction) playAppSound: (id) sender {
// [appSoundPlayer play];
// playing = YES;
// [appSoundButton setEnabled: NO];
}
// delegate method for the audio route change alert view; follows the protocol specified
// in the UIAlertViewDelegate protocol.
- (void) alertView: routeChangeAlertView clickedButtonAtIndex: buttonIndex {
if ((NSInteger) buttonIndex == 1) {
[appSoundPlayer play];
} else {
[appSoundPlayer setCurrentTime: 0];
[appSoundButton setEnabled: YES];
}
[routeChangeAlertView release];
}
#pragma mark AV Foundation delegate methods____________
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) appSoundPlayer successfully: (BOOL) flag {
}
- (void) audioPlayerBeginInterruption: player {
}
- (void) audioPlayerEndInterruption: player {
}
#pragma mark Table view delegate methods________________
// Invoked when the user taps the Done button in the table view.
- (void) musicTableViewControllerDidFinish: (MusicTableViewController *) controller {
[self dismissModalViewControllerAnimated: YES];
}
#pragma mark Application setup____________________________
#if TARGET_IPHONE_SIMULATOR
#warning *** Simulator mode: iPod library access works only when running on a device.
#endif
//play audio 2
- (void)playAudio2:(NSString*) name type:(NSString*)type
{
[self stopAudio];
[audioPlayer stop];
[audioPlayer release];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:name
ofType:type]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
[audioPlayer play];
}
-(void)playAudio
{
[appSoundPlayer play];
}
- (void)stopAudio
{
[appSoundPlayer stop];
}
// Configure the application.
- (void) viewDidLoad {
[super viewDidLoad];
[self setPlayedMusicOnce: NO];
[self setNoArtworkImage: [UIImage imageNamed: #"no_artwork.png"]];
[self setPlayBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay
target: self
action: #selector (playOrPauseMusic:)]];
[self setPauseBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPause
target: self
action: #selector (playOrPauseMusic:)]];
[addOrShowMusicButton setTitle: NSLocalizedString (#"Add Music", #"Title for 'Add Music' button, before user has chosen some music")
forState: UIControlStateNormal];
[appSoundButton setTitle: NSLocalizedString (#"Play App Sound", #"Title for 'Play App Sound' button")
forState: UIControlStateNormal];
[nowPlayingLabel setText: NSLocalizedString (#"Instructions", #"Brief instructions to user, shown at launch")];
// Configure a timer to change the background color. The changing color represents an
// application that is doing something else while iPod music is playing.
[self setBackgroundColorTimer: [NSTimer scheduledTimerWithTimeInterval: 3.5
target: self
selector: #selector (updateBackgroundColor)
userInfo: nil
repeats: YES]];
[self setupAudioSession];
}
// Invoked by the backgroundColorTimer.
- (void) updateBackgroundColor {
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration: 3.0];
CGFloat redLevel = rand() / (float) RAND_MAX;
CGFloat greenLevel = rand() / (float) RAND_MAX;
CGFloat blueLevel = rand() / (float) RAND_MAX;
self.view.backgroundColor = [UIColor colorWithRed: redLevel
green: greenLevel
blue: blueLevel
alpha: 1.0];
[UIView commitAnimations];
}
#pragma mark Application state management_____________
- (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.
}
- (void) viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(void) setupAudioSession
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError){/* Handle Error COndition*/}
NSError *activationError = nil;
[audioSession setActive:YES error:&activationError];
if (activationError){
/*handle error*/
}
}
// just for test , delete after
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
+(void) myClassMethod{
NSLog(#"Class Called ok");
}
- (void)dealloc {
/*
// This sample doesn't use libray change notifications; this code is here to show how
// it's done if you need it.
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] endGeneratingLibraryChangeNotifications];
*/
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer endGeneratingPlaybackNotifications];
[musicPlayer release];
[artworkItem release];
[backgroundColorTimer invalidate];
[backgroundColorTimer release];
[navigationBar release];
[noArtworkImage release];
[nowPlayingLabel release];
[pauseBarButton release];
[playBarButton release];
[soundFileURL release];
[userMediaItemCollection release];
[super dealloc];
}
I am sending the file name from my playlist to my player through
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
and i load my playlist from my mainviewcontroller using the UIModalTransition in the method
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
As you can see when i load my playlist i tell the player to stop playing through
[audioPlayer stop];
but for some reason it failes to stop playing, therefore creating an overlap of sounds.
This is my problem which i'm trying to figure out.
Thank you
and best regards!

No known class method for selector 'sharedStore'

Have a singleton class for BNRItemStore, but when I tried to call it, I get the above error which causes an ARC issue. Have commented out the error.
DetailViewController.m
#import "DetailViewController.h"
#import "BNRItem.h"
#import "BNRImageStore.h"
#import "BNRItemStore.h"
#implementation DetailViewController
#synthesize item;
-(id)initForNewItem:(BOOL)isNew
{
self = [super initWithNibName:#"DetailViewController" bundle:nil];
if(self){
if (isNew) {
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(save:)];
[[self navigationItem] setRightBarButtonItem:doneItem];
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel:)];
[[self navigationItem] setLeftBarButtonItem:cancelItem];
}
}
return self;
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
#throw [NSException exceptionWithName:#"Wrong initializer"
reason:#"Use initForNewItem:"
userInfo:nil];
return nil;
}
-(void)viewDidLoad
{
[super viewDidLoad];
UIColor *clr = nil;
if ([[UIDevice currentDevice]userInterfaceIdiom]== UIUserInterfaceIdiomPad) {
clr = [UIColor colorWithRed:0.875 green:0.88 blue:0.91 alpha:1];
} else {
clr = [UIColor groupTableViewBackgroundColor];
}
[[self view]setBackgroundColor:clr];
}
- (void)viewDidUnload {
nameField = nil;
serialNumberField = nil;
valueField = nil;
dateLabel = nil;
imageView = nil;
[super viewDidUnload];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[nameField setText:[item itemName]];
[serialNumberField setText:[item serialNumber]];
[valueField setText:[NSString stringWithFormat:#"%d", [item valueInDollars]]];
// Create a NSDateFormatter that will turn a date into a simple date string
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// Use filtered NSDate object to set dateLabel contents
[dateLabel setText:[dateFormatter stringFromDate:[item dateCreated]]];
NSString *imageKey = [item imageKey];
if (imageKey) {
// Get image for image key from image store
UIImage *imageToDisplay = [[BNRImageStore sharedStore]imageForKey:imageKey];
// Use that image to put on the screen in imageview
[imageView setImage:imageToDisplay];
} else {
// Clear the imageview
[imageView setImage:nil];
}
}
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Clear first responder
[[self view]endEditing:YES];
// "Save" changes to item
[item setItemName:[nameField text]];
[item setSerialNumber:[serialNumberField text]];
[item setValueInDollars:[[valueField text] intValue]];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io
{
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
return YES;
} else {
return (io==UIInterfaceOrientationPortrait);
}
}
-(void)setItem:(BNRItem *)i
{
item = i;
[[self navigationItem] setTitle:[item itemName]];
}
- (IBAction)takePicture:(id)sender {
if ([imagePickerPopover isPopoverVisible]) {
// If the popover is already up, get rid of it
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
return;
}
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc]init];
// If our device has a camera, we want to take a picture, otherwise, we
// just pick from the photo library
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
// This line of code will generate a warning right now, ignore it
[imagePicker setDelegate:self];
//Place image picker on the screen
// Check for iPad device before instantiating the popover controller
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// Create a new popover controller that will display the imagepicker
imagePickerPopover = [[UIPopoverController alloc]initWithContentViewController:imagePicker];
[imagePickerPopover setDelegate:self];
// Display the popover controller; sender
// is the camera bar button item
[imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentViewController:imagePicker animated:YES completion:nil];
}
}
}
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
NSLog(#"User dismissed popover");
imagePickerPopover = nil;
}
- (IBAction)backgroundTapped:(id)sender {
[[self view]endEditing:YES];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *oldKey = [item imageKey];
// Did the item already have an image?
if (oldKey) {
// Delete the old image
[[BNRImageStore sharedStore]deleteImageForKey:oldKey];
}
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Create a CFUUID object - it knows how to create unique identifier strings
CFUUIDRef newUniqueID = CFUUIDCreate(kCFAllocatorDefault);
// Create a string from unique identifier
CFStringRef newUniqueIDString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueID); // Incompatible integer to pointer conversion initializing
// Use that unique ID to set our item's imageKey
NSString *key = (__bridge NSString *)newUniqueIDString;
[item setImageKey:key];
// Store image in the BNRImageStore with this key
[[BNRImageStore sharedStore] setImage:image forKey:[item imageKey]];
CFRelease(newUniqueIDString);
CFRelease(newUniqueID);
[imageView setImage:image];
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// If on the phone, the image picker is presented modally. Dismiss it.
[self dismissViewControllerAnimated:YES completion:nil];
} else {
// If on the pad, the image picker is in the popover. Dismiss the popover.
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
-(void)save:(id)sender
{
[[self presentingViewController]dismissViewControllerAnimated:YES
completion:nil];
}
-(void)cancel:(id)sender
{
// If the user cancelled, then remove the BNRItem from the store
[[BNRItemStore sharedStore]removeItem:item]; // No known class method for selector 'sharedStore'
[[self presentingViewController]dismissViewControllerAnimated:YES completion:nil];
}
DetailViewController.h
#import <UIKit/UIKit.h>
#class BNRItem;
#interface DetailViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate,UITextFieldDelegate, UIPopoverControllerDelegate>
{
__weak IBOutlet UITextField *nameField;
__weak IBOutlet UITextField *serialNumberField;
__weak IBOutlet UITextField *valueField;
__weak IBOutlet UILabel *dateLabel;
__weak IBOutlet UIImageView *imageView;
UIPopoverController *imagePickerPopover;
}
#property(nonatomic,strong)BNRItem *item;
-(id)initForNewItem:(BOOL)isNew;
- (IBAction)takePicture:(id)sender;
- (IBAction)backgroundTapped:(id)sender;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#implementation BNRItemStore
+ (BNRItemStore *)defaultStore
{
static BNRItemStore *defaultStore = nil;
if(!defaultStore)
defaultStore = [[super allocWithZone:nil] init];
return defaultStore;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}
- (id)init
{
self = [super init];
if(self) {
allItems = [[NSMutableArray alloc] init];
}
return self;
}
- (void)removeItem:(BNRItem *)p
{
[allItems removeObjectIdenticalTo:p];
}
- (NSArray *)allItems
{
return allItems;
}
- (void)moveItemAtIndex:(int)from
toIndex:(int)to
{
if (from == to) {
return;
}
// Get pointer to object being moved so we can re-insert it
BNRItem *p = [allItems objectAtIndex:from];
// Remove p from array
[allItems removeObjectAtIndex:from];
// Insert p in array at new location
[allItems insertObject:p atIndex:to];
}
- (BNRItem *)createItem
{
BNRItem *p = [BNRItem randomItem];
[allItems addObject:p];
return p;
}
#end
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
{
NSMutableArray *allItems;
}
+ (BNRItemStore *)defaultStore;
- (void)removeItem:(BNRItem *)p;
- (NSArray *)allItems;
- (BNRItem *)createItem;
- (void)moveItemAtIndex:(int)from
toIndex:(int)to;
#end
You are calling +sharedStore on BNRItemStore where your error occurs. This is because it really does not exist according to the code you posted.
All of the others calling +sharedStore are using the one presumably made available by BNRImageStore which you didn't provide. I assume it exists in that class? :)
In short, change:
[[BNRItemStore sharedStore]removeItem:item];
to
[[BNRImageStore sharedStore]removeItem:item];

Async Image download a UITableView's cellForRowAtIndexPath not always called

I using Apple's LazyTableImages sample to async download images for UITableViewCells. The main difference is that I'm saving a copy of the file to the Documents folder so that it doesn't need to be downloaded all the time. The method below is called by the class responsible for downloading the image
- (void)imageDidLoad:(NSIndexPath *)indexPath
{
AsyncImage *aImage = [imageDownloadsInProgress objectForKey:indexPath];
if (aImage != nil)
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:aImage.indexPathInTableView];
cell.imageView.image = aImage.image;
}
}
When the image is not on the device, the download goes fine and the image is displayed. However when the image is on the device the image is not displayed and the cell variable is null.
The code for the AsyncImage is:
//
// AsyncImgView.m
// BelfastChamberOfCommerce
//
// Created by markpirvine on 23/06/2011.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "AsyncImage.h"
#import "AppManager.h"
#define kAppIconHeight 48
#interface AsyncImage ()
#property (nonatomic, retain) NSString *fileUrl;
#end
#implementation AsyncImage
#synthesize imageUrl, fileUrl;
#synthesize image;
#synthesize indexPathInTableView;
#synthesize delegate;
- (void)dealloc
{
[imageUrl release];
[fileUrl release];
[image release];
[indexPathInTableView release];
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
- (void)loadImage
{
if (connection != nil)
{
[connection release];
}
if (data != nil)
{
[data release];
}
if([self.imageUrl length] > 0)
{
self.fileUrl = [[[AppManager sharedInstance] getCacheLocation] stringByAppendingPathComponent:[[self.imageUrl componentsSeparatedByString:#"/"] lastObject]];
if([[NSFileManager defaultManager] fileExistsAtPath:self.fileUrl] == YES)
{
self.image = [UIImage imageWithContentsOfFile:self.fileUrl];
[self deliverImage];
}
else
{
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.imageUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
}
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData
{
if (data == nil)
{
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[connection release];
connection = nil;
UIImage *iTmp = [[UIImage alloc] initWithData:data];
if (iTmp.size.width != kAppIconHeight && iTmp.size.height != kAppIconHeight)
{
CGSize itemSize = CGSizeMake(kAppIconHeight, kAppIconHeight);
UIGraphicsBeginImageContext(itemSize);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[iTmp drawInRect:imageRect];
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
else
{
self.image = iTmp;
}
[UIImageJPEGRepresentation(self.image, 1.0) writeToFile:self.fileUrl atomically:YES];
[iTmp release];
[data release];
data = nil;
[self deliverImage];
}
- (void)deliverImage
{
[delegate imageDidLoad:self.indexPathInTableView];
}
- (void)cancelDownload
{
[connection cancel];
connection = nil;
data = nil;
}
#end
Any help would be greatly appreciated
I suggest using one of the open source classes for async download of images that has built-in support for caching. The one that I'm using is cached image for iOS.