Audio playing not working when ios device is locked - avaudioplayer

I am doing the following things to make audio play when an iOS device is locked, but it doesn't work.
UIBackgroundModes key (with the value audio) in Info.plist file.
set up audio session
code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self createAudioSession];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"jgj" ofType:#"mp3"];
NSURL *url = [NSURL fileURLWithPath:soundFilePath];
NSLog(#"%#",[url path]);
NSError* error;
self.audioPlayer=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (self.audioPlayer == nil)
NSLog(#"%#",[error description]);
else
{
self.audioPlayer.numberOfLoops=-1;
[self.audioPlayer play];
}
}
-(void)createAudioSession
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
// Use this code to allow the app sound to continue to play when the screen is locked.
NSError* error=nil;
BOOL ok=[audioSession setCategory: AVAudioSessionCategoryPlayback error: &error];
if(!ok)
NSLog(#"%#",[error description]);
else
NSLog(#"hello");
ok=[audioSession setActive:YES error:&error];
if(!ok)
NSLog(#"%#",[error description]);
else
NSLog(#"world");
}

Related

How to get a video PHAsset disk file size?

I'm trying to determine the file size on disk of a PHAsset video.
The following code is returning am error "The file “IMG_0188.mov” couldn’t be opened because you don’t have permission to view it."
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset *avAsset, AVAudioMix *audioMix, NSDictionary *info) {
videoURL = [(AVURLAsset*)avAsset URL];
NSNumber *videoDiskFileSize;
NSError *error;
[videoURL getResourceValue:&videoDiskFileSize forKey:NSURLFileSizeKey error:&error];
if(error){
NSLog(#"ERROR %#", error.localizedDescription);
}
NSLog(#"size is %f",[videoDiskFileSize floatValue]/(1024.0*1024.0));
}];
Here's the correct way to do it.
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestExportSessionForVideo:asset options:options exportPreset:AVAssetExportPresetHighestQuality resultHandler:^(AVAssetExportSession *exportSession, NSDictionary *info) {
CMTime videoDuration = CMTimeMultiplyByFloat64(exportSession.asset.duration, 1);
exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, videoDuration);
NSLog(#"Byyte size = %lld", exportSession.estimatedOutputFileLength);
videoSize = exportSession.estimatedOutputFileLength;
}];

NSOperationQueue order

I try create a queue for downloads some file, so I create an NSOperation subclass and then the queue, at the end of the queue I want to send a notification, the problem is that I see into the console the endQueue log before queue is finished.
The log is this:
....
Download finished
Download finished
Download finished
Queue finished
Download finished
Download finished
Download finished
...
while I need to have
....
Download finished
Download finished
Download finished
Download finished
Download finished
Download finished
Queue finished
This is my NSOperation subclass
- (id) initWithDictionary:(NSDictionary*)dict {
self = [super init];
if (self) {
[self setFileDict:dict];
}
return self;
}
- (void) main {
[self runOperation];
}
- (void) runOperation {
NSURL *urlFile = [NSURL URLWithString:[fileDict objectForKey:#"urlStr"];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:urlFile]
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (data) {
[data writeToFile:pathFile atomically:YES];
[notificationCenter postNotificationName:#"Download finished" object:nil];
}
}];
}
from another class I create and execute the queue in this way
self.operationQueue = [[NSOperationQueue alloc] init];;
[self.operationQueue setMaxConcurrentOperationCount:1];
for (NSDictionary *dict in fileDaScaricare) {
DownloadOperation *downloadOperation = [[DownloadOperation alloc] initWithDictionary:dict];
[self.operationQueue addOperation:downloadOperation];
}
[self.operationQueue addOperationWithBlock:^{
NSLog(#"Queue finished");
[notificationCenter postNotificationName:#"endFile" object:nil];
}];
You can try this:
- (void) runOperation {
NSURL *urlFile = [NSURL URLWithString:[fileDict objectForKey:#"urlStr"];
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:urlFile];
self.downloadConnection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self];
// keeps the NSOperation alive for the during of the NSURLConnection!
[self.downloadConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.downloadConnection start];
}
Then you can observe the notification in NSURLConnectionDelegate methods:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[notificationCenter postNotificationName:#"Download finished" object:nil];
}

Posting user profile pic to twitter giving Error 131

When trying to post a users profile pic to twitter, I am getting Error code 131 response back:
2013-12-06 19:17:29.854 Tweetly[8131:60b] {
errors = (
{
code = 131;
message = "Internal error";
}
);
}
Twitters website lists this:
"Corresponds with an HTTP 500 - An unknown internal error occurred."
Here is my code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//Code for store image
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
UIImage *scaledImage = [self imageWithImage:image convertToSize:CGSizeMake(500, 500)];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(scaledImage)];
[self uploadPictureWithData:imageData];
}
- (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size {
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *destImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return destImage;
}
- (void)uploadPictureWithData:(NSData *)imageData {
// Get the twitter feed
NSURL *requestURL = [NSURL URLWithString:#"https://api.twitter.com/1.1/account/update_profile_image.json"];
// Set up proper parameters
NSMutableDictionary *timelineParameters = [[NSMutableDictionary alloc] init];
[timelineParameters setObject:imageData forKey:#"image"];
[timelineParameters setObject:#"1" forKey:#"skip_status"];
// Create the Social Request
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:requestURL parameters:timelineParameters];
postRequest.account = self.delegate.userAccount;
// Perform the request
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
// Check if we reached the reate limit
if ([urlResponse statusCode] == 429) {
// Rate limit reached
// Display an alert letting the user know we have hit the rate limit
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kRateLimitTitle
message:kRateLimitMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
return;
}
// Check if there was an error
if (error) {
NSLog(#"Error: %#", error.localizedDescription);
return;
}
// Check if there is some response data
if (responseData) {
NSError *jsonError = nil;
NSMutableArray *feedData = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];
if (!jsonError) {
// Check the response data
NSLog(#"%#", feedData);
} else {
// Alert the user with the error
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
message:kErrorMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
}
} else {
// Alert the user with the error
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
message:kErrorMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
}
});
}];
}
Any idea what the issue might be? I initially thought it was because the image was too big, so I added the method for scaling the image down to 500 x 500, but I get the same error.
This error happens while running on both the device and the simulator.
Does anyone see where the problem is or have any extra insight? Thanks!
In my tests, images larger than 1000x1000px are not downscaled synchronously, throwing the 131 response code. Undocumented, unfortunately.
Make sure the image is <700kb and smaller than 1000x1000px.
https://dev.twitter.com/rest/reference/post/account/update_profile_image

ZUUIRevealController - Memory allocations keeps on increasing & slow UIAlertView & UIActionsheet

I am starting with new iOS app in which I have to use Reveal control. So I planned to use great ZUUIRevealController library. I just created UI for 2 - 3 screens . In one of those screen I have to shown UIAlertView & UIActionsheet. But I realised that UIAlertView & UIActionsheet shows very slowly (it adds black overlay first & then shows UIAlertView/UIActionsheet, kind of alert view hangs while showing. Animation is not smooth). I didn't added any logic for coding just created the UI. I didn't use any background thread / dispatch_asyn(). So there is no issue of updating UI from background thread. So I checked the memory leaks & allocations. I didn't see any memory leaks , but memory allocations keeps on increasing while I reveal the menu & push new view controller. It doesn't decrese when I pop the view controller. Here are the screenshots :
1) When app launches
2) After some time , when I push new view controller, pop view controller
I know ZUUIRevealController library creates new instance of view controller every time I select a row from Menu. So I crated the instance variables of view controllers in .h file , but still I have same problem.
Here is my code
// AppDelegate.m
// On SplashViewController , I decide whether to show menu or Login screen
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.splashViewController = [[SplashViewController alloc]initWithNibName:#"SplashViewController" bundle:nil];
self.window.rootViewController = self.splashViewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
[self customizeUIControlsAppearance];
return YES;
}
// SplashViewController.m
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
BOOL isLoggedIn = YES;
if(isLoggedIn){
[self showMenuViewController];
}
else{
[self showStartUpViewController];
}
}
-(void)showStartUpViewController
{
StartUpViewController *startUpViewController = [[StartUpViewController alloc]initWithNibName:#"StartUpViewController" bundle:nil];
UINavigationController *navController=[[UINavigationController alloc] initWithRootViewController:startUpViewController];
[self presentViewController:navController animated:NO completion:^{
}];
}
-(void)showMenuViewController
{
MenuViewController *menuViewController=[[MenuViewController alloc] init];
CategoryViewController *categoryViewController=[[CategoryViewController alloc]initWithNibName:#"CategoryViewController" bundle:nil];
categoryViewController.isViewControllerShownFromMenu = YES;
UINavigationController *navController=[[UINavigationController alloc] initWithRootViewController:categoryViewController];
RevealController *revealController=[[RevealController alloc] initWithFrontViewController:navController rearViewController:menuViewController];
[self presentViewController:revealController animated:NO completion:^{
}];
}
// MenuViewController.m
// SettingsViewController & NewsViewController are decalred in .h file with property & syntheszie
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
RevealController *revealController = [self.parentViewController isKindOfClass:[RevealController class]] ? (RevealController *)self.parentViewController : nil;
// Switch using Section Number
switch (indexPath.section) {
case OTHER_SECTION:
switch (indexPath.row) {
case NEWS:
[self showNewsViewControllerUsingRevealController:revealController];
break;
case SETTINGS:
[self showSettingsViewControllerUsingRevealController:revealController];
break;
default:
break;
}
break;
default:
break;
}
}
#pragma mark - Show News & Settings View Controllers
-(void)showNewsViewControllerUsingRevealController:(RevealController*)revealController
{
if ([revealController.frontViewController isKindOfClass:[UINavigationController class]] && ![((UINavigationController *)revealController.frontViewController).topViewController isKindOfClass:[NewsViewController class]])
{
if(!self.newsViewController)
self.newsViewController = [[NewsViewController alloc] initWithNibName:#"NewsViewController" bundle:nil];
self.newsViewController.isViewControllerShownFromMenu = YES;
UINavigationController *navigationController= [[UINavigationController alloc] initWithRootViewController:self.newsViewController];
[revealController setFrontViewController:navigationController animated:NO];
}
else
{
[revealController revealToggle:self];
}
}
-(void)showSettingsViewControllerUsingRevealController:(RevealController*)revealController
{
if ([revealController.frontViewController isKindOfClass:[UINavigationController class]] && ![((UINavigationController *)revealController.frontViewController).topViewController isKindOfClass:[SettingsViewController class]])
{
if(!self.settingsViewController)
self.settingsViewController= [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:nil];
self.settingsViewController.isViewControllerShownFromMenu = YES;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.settingsViewController];
[revealController setFrontViewController:navigationController animated:NO];
}
else
{
[revealController revealToggle:self];
}
}
// Code for shwoing UIAlertView & UIActionsheet
-(void)showAlertWithTitle:(NSString*)title andMessage:(NSString*)message
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:title message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
-(void)btnInviteTapped:(id)sender event:(UIEvent*)event
{
UIActionSheet *actionSheet = [[UIActionSheet alloc]initWithTitle:NSLocalizedString(#"FRIENDS_VC:INVIT_ACTIONSHEET_TITLE", nil) delegate:self cancelButtonTitle:NSLocalizedString(#"FRIENDS_VC:ACTIONSHEET_CANCEL_BUTTON",nil) destructiveButtonTitle:nil otherButtonTitles:NSLocalizedString(#"FRIENDS_VC:ACTIONSHEET_SMS_BUTTON",nil),NSLocalizedString(#"FRIENDS_VC:ACTIONSHEET_EMAIL_BUTTON",nil), nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[actionSheet showInView:self.view];
}
By the way I have 11 menu items.
My Login & Regsiter flow is not embedded in MenuViewController. On Login & REgsiter , UIAlertView & UIActionSheet shows smoothly.
Any idea whats going wrong here ? Did I make some mistake in coding ?
Why my UIAlertView & UIActionsheet are not showing smoothly ?
Any kind of help is appreciated. Thanks.

ASIHTTPRequest backed RestKit object mapping

We must support some old code that runs using ASIHTTPRequest, but we want the object mapping and core data support provided by RestKit. Does anyone know of any way of "gluing" these two together?
I picture using ASIHTTPRequest for the requests and someone manually forwarding the payload over to RestKit.
Ok, so this wasn't too hard after all. Here is a class I wrote just for this (no disclaimers, it works for us and may be useful for someone else). You can use this as a direct replacement to the standard RKObjectLoader class.
.h file
#import <RestKit/RestKit.h>
#import "ASIFormDataRequest.h"
#interface ASIHTTPObjectLoader : ASIFormDataRequest <RKObjectMapperDelegate> {
RKObjectManager* _objectManager;
RKObjectMapping* _objectMapping;
RKObjectMappingResult* _result;
RKObjectMapping* _serializationMapping;
NSString* _serializationMIMEType;
NSObject* _sourceObject;
NSObject* _targetObject;
}
#property (nonatomic, retain) RKObjectMapping* objectMapping;
#property (nonatomic, readonly) RKObjectManager* objectManager;
#property (nonatomic, readonly) RKObjectMappingResult* result;
#property (nonatomic, retain) RKObjectMapping* serializationMapping;
#property (nonatomic, retain) NSString* serializationMIMEType;
#property (nonatomic, retain) NSObject* sourceObject;
#property (nonatomic, retain) NSObject* targetObject;
- (void) setDelegate:(id<RKObjectLoaderDelegate>)delegate;
+ (id)loaderWithResourcePath:(NSString*)resourcePath objectManager: (RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate;
- (id)initWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate;
- (void)handleResponseError;
#end
.m file
#import "ASIHTTPObjectLoader.h"
#interface ASIFormDataRequest (here)
- (void) reportFailure;
- (void) reportFinished;
#end
#implementation ASIHTTPObjectLoader
#synthesize objectManager = _objectManager;
#synthesize targetObject = _targetObject, objectMapping = _objectMapping;
#synthesize result = _result;
#synthesize serializationMapping = _serializationMapping;
#synthesize serializationMIMEType = _serializationMIMEType;
#synthesize sourceObject = _sourceObject;
- (void) setDelegate:(id<RKObjectLoaderDelegate>)_delegate {
[super setDelegate: _delegate];
}
+ (id)loaderWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)_delegate {
return [[[self alloc] initWithResourcePath:resourcePath objectManager:objectManager delegate:_delegate] autorelease];
}
- (id)initWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)_delegate {
self = [super initWithURL: [objectManager.client URLForResourcePath: resourcePath]];
if ( self ) {
self.delegate = _delegate;
_objectManager = objectManager;
}
return self;
}
- (void)dealloc {
// Weak reference
_objectManager = nil;
[_sourceObject release];
_sourceObject = nil;
[_targetObject release];
_targetObject = nil;
[_objectMapping release];
_objectMapping = nil;
[_result release];
_result = nil;
[_serializationMIMEType release];
[_serializationMapping release];
[super dealloc];
}
- (void) reset {
[_result release];
_result = nil;
}
- (void)finalizeLoad:(BOOL)successful error:(NSError*)_error {
//_isLoading = NO;
if (successful) {
//_isLoaded = YES;
if ([self.delegate respondsToSelector:#selector(objectLoaderDidFinishLoading:)]) {
[self.delegate performSelectorOnMainThread:#selector(objectLoaderDidFinishLoading:)
withObject:self waitUntilDone:YES];
}
[super reportFinished];
/*
NSDictionary* userInfo = [NSDictionary dictionaryWithObject:_response
forKey:RKRequestDidLoadResponseNotificationUserInfoResponseKey];
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidLoadResponseNotification
object:self
userInfo:userInfo];
*/
} else {
NSDictionary* _userInfo = [NSDictionary dictionaryWithObject:(_error ? _error : (NSError*)[NSNull null])
forKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey];
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFailWithErrorNotification
object:self
userInfo:_userInfo];
}
}
// Invoked on the main thread. Inform the delegate.
- (void)informDelegateOfObjectLoadWithResultDictionary:(NSDictionary*)resultDictionary {
NSAssert([NSThread isMainThread], #"RKObjectLoaderDelegate callbacks must occur on the main thread");
RKObjectMappingResult* result = [RKObjectMappingResult mappingResultWithDictionary:resultDictionary];
if ([self.delegate respondsToSelector:#selector(objectLoader:didLoadObjectDictionary:)]) {
[self.delegate objectLoader: (RKObjectLoader*)self didLoadObjectDictionary:[result asDictionary]];
}
if ([self.delegate respondsToSelector:#selector(objectLoader:didLoadObjects:)]) {
[self.delegate objectLoader: (RKObjectLoader*)self didLoadObjects:[result asCollection]];
}
if ([self.delegate respondsToSelector:#selector(objectLoader:didLoadObject:)]) {
[self.delegate objectLoader: (RKObjectLoader*)self didLoadObject:[result asObject]];
}
[self finalizeLoad:YES error:nil];
}
#pragma mark - Subclass Hooks
/**
Overloaded by ASIHTTPManagedObjectLoader to serialize/deserialize managed objects
at thread boundaries.
#protected
*/
- (void)processMappingResult:(RKObjectMappingResult*)result {
NSAssert(isSynchronous || ![NSThread isMainThread], #"Mapping result processing should occur on a background thread");
[self performSelectorOnMainThread:#selector(informDelegateOfObjectLoadWithResultDictionary:) withObject:[result asDictionary] waitUntilDone:YES];
}
#pragma mark - Response Object Mapping
- (RKObjectMappingResult*)mapResponseWithMappingProvider:(RKObjectMappingProvider*)mappingProvider toObject:(id)targetObject error:(NSError**)_error {
NSString* MIMEType = [[self responseHeaders] objectForKey: #"Content-Type"];
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType: MIMEType];
NSAssert1(parser, #"Cannot perform object load without a parser for MIME Type '%#'", MIMEType);
// Check that there is actually content in the response body for mapping. It is possible to get back a 200 response
// with the appropriate MIME Type with no content (such as for a successful PUT or DELETE). Make sure we don't generate an error
// in these cases
id bodyAsString = [self responseString];
if (bodyAsString == nil || [[bodyAsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) {
RKLogDebug(#"Mapping attempted on empty response body...");
if (self.targetObject) {
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionaryWithObject:self.targetObject forKey:#""]];
}
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionary]];
}
id parsedData = [parser objectFromString:bodyAsString error:_error];
if (parsedData == nil && _error) {
return nil;
}
// Allow the delegate to manipulate the data
if ([self.delegate respondsToSelector:#selector(objectLoader:willMapData:)]) {
parsedData = [[parsedData mutableCopy] autorelease];
[self.delegate objectLoader: (RKObjectLoader*)self willMapData:&parsedData];
}
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider];
mapper.targetObject = targetObject;
mapper.delegate = self;
RKObjectMappingResult* result = [mapper performMapping];
// Log any mapping errors
if (mapper.errorCount > 0) {
RKLogError(#"Encountered errors during mapping: %#", [[mapper.errors valueForKey:#"localizedDescription"] componentsJoinedByString:#", "]);
}
// The object mapper will return a nil result if mapping failed
if (nil == result) {
// TODO: Construct a composite error that wraps up all the other errors. Should probably make it performMapping:&error when we have this?
if (_error) *_error = [mapper.errors lastObject];
return nil;
}
return result;
}
- (RKObjectMappingResult*)performMapping:(NSError**)_error {
NSAssert( isSynchronous || ![NSThread isMainThread], #"Mapping should occur on a background thread");
RKObjectMappingProvider* mappingProvider;
if (self.objectMapping) {
NSString* rootKeyPath = self.objectMapping.rootKeyPath ? self.objectMapping.rootKeyPath : #"";
RKLogDebug(#"Found directly configured object mapping, creating temporary mapping provider for keyPath %#", rootKeyPath);
mappingProvider = [[RKObjectMappingProvider new] autorelease];
[mappingProvider setMapping:self.objectMapping forKeyPath:rootKeyPath];
} else {
RKLogDebug(#"No object mapping provider, using mapping provider from parent object manager to perform KVC mapping");
mappingProvider = self.objectManager.mappingProvider;
}
return [self mapResponseWithMappingProvider:mappingProvider toObject:self.targetObject error:_error];
}
- (void)performMappingOnBackgroundThread {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSError* _error = nil;
_result = [[self performMapping:&_error] retain];
NSAssert(_result || _error, #"Expected performMapping to return a mapping result or an error.");
if (self.result) {
[self processMappingResult:self.result];
} else if (_error) {
[self failWithError: _error];
}
[pool drain];
}
- (BOOL)canParseMIMEType:(NSString*)MIMEType {
if ([[RKParserRegistry sharedRegistry] parserForMIMEType: MIMEType]) {
return YES;
}
RKLogWarning(#"Unable to find parser for MIME Type '%#'", MIMEType);
return NO;
}
- (BOOL)isResponseMappable {
if ([self responseStatusCode] == 503) {
[[NSNotificationCenter defaultCenter] postNotificationName:RKServiceDidBecomeUnavailableNotification object:self];
}
NSString* MIMEType = [[self responseHeaders] objectForKey: #"Content-Type"];
if ( error ) {
[self.delegate objectLoader: (RKObjectLoader*)self didFailWithError: error];
[self finalizeLoad:NO error: error];
return NO;
} else if ([self responseStatusCode] == 204) {
// The No Content (204) response will never have a message body or a MIME Type. Invoke the delegate with self
[self informDelegateOfObjectLoadWithResultDictionary:[NSDictionary dictionaryWithObject:self forKey:#""]];
return NO;
} else if (NO == [self canParseMIMEType: MIMEType]) {
// We can't parse the response, it's unmappable regardless of the status code
RKLogWarning(#"Encountered unexpected response with status code: %ld (MIME Type: %#)", (long) [self responseStatusCode], MIMEType);
NSError* _error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKObjectLoaderUnexpectedResponseError userInfo:nil];
if ([self.delegate respondsToSelector:#selector(objectLoaderDidLoadUnexpectedResponse:)]) {
[self.delegate objectLoaderDidLoadUnexpectedResponse: (RKObjectLoader*)self];
} else {
[self.delegate objectLoader: (RKObjectLoader*)self didFailWithError: _error];
}
// NOTE: We skip didFailLoadWithError: here so that we don't send the delegate
// conflicting messages around unexpected response and failure with error
[self finalizeLoad:NO error:_error];
return NO;
} else if (([self responseStatusCode] >= 400 && [self responseStatusCode] < 500) ||
([self responseStatusCode] >= 500 && [self responseStatusCode] < 600) ) {
// This is an error and we can map the MIME Type of the response
[self handleResponseError];
return NO;
}
return YES;
}
- (void)handleResponseError {
// Since we are mapping what we know to be an error response, we don't want to map the result back onto our
// target object
NSError* _error = nil;
RKObjectMappingResult* result = [self mapResponseWithMappingProvider:self.objectManager.mappingProvider toObject:nil error:&_error];
if (result) {
_error = [result asError];
} else {
RKLogError(#"Encountered an error while attempting to map server side errors from payload: %#", [_error localizedDescription]);
}
[self.delegate objectLoader: (RKObjectLoader*)self didFailWithError:_error];
[self finalizeLoad:NO error:_error];
}
#pragma mark - RKRequest & RKRequestDelegate methods
- (void) reportFailure {
[self.delegate objectLoader: (RKObjectLoader*)self didFailWithError:error];
[super reportFailure];
}
- (void)reportFinished {
NSAssert([NSThread isMainThread], #"RKObjectLoaderDelegate callbacks must occur on the main thread");
if ([self isResponseMappable]) {
// Determine if we are synchronous here or not.
if (isSynchronous) {
NSError* _error = nil;
_result = [[self performMapping:&_error] retain];
if (self.result) {
[self processMappingResult:self.result];
} else {
[self performSelectorInBackground:#selector(failWithError:) withObject:_error];
}
[super reportFinished];
} else {
[self performSelectorInBackground:#selector(performMappingOnBackgroundThread) withObject:nil];
}
}
}
I do the following in my unit test code to make sure my object mappings are working
NSDictionary *headers = [NSDictionary dictionaryWithObjectsAndKeys:#"application/json", #"X-RESTKIT-CACHED-MIME-TYPE",
#"200", #"X-RESTKIT-CACHED-RESPONSE-CODE",
#"application/json; charset=utf-8", #"Content-Type",
nil];
NSURL *url = [[NSURL alloc] initWithString:#""]; //need a url to create a dummy RKRequest
RKRequest *request = [RKRequest requestWithURL:url];
[url release];
//Create a dummy response with the data payload
RKResponse *response = [[[RKResponse alloc] initWithRequest:request
body:myData //myData is NSData loaded from my file on disk in this case
headers:headers] autorelease];
RKURL *rkURL = [[RKURL alloc] initWithString:#"https://api.twitter.com"];
RKManagedObjectLoader *loader = [[RKManagedObjectLoader alloc] initWithURL:rkURL
mappingProvider:self.objectManager.mappingProvider
objectStore:self.objectManager.objectStore];
loader.delegate = self;
loader.objectMapping = self.objectMapping; //I pass the object mapping to use here.
[loader didFinishLoad:response]; //Given a response and request, Restkit will parse the response and call the usual delegates
You might be able to do somthing similar as well to grab the response data from ASIHTTPRequest and pass it on to RestKit

Resources