I am trying to map attributes to a class in RESTKit without a nested KVC and without much luck i keep getting nil for my values even though the response contains values.
I have read over the object mapping manual and tried it with path patterns without path patterns etc. Does anyone have any insight?
Request and Response from server
2014-06-16 15:58:07.162 game[5961:60b] T
restkit.network:RKObjectRequestOperation.m:178 POST 'https://api.myURL.com/api/0_0_1/notify/player':
request.headers=
{
Accept = "application/json";
"Accept-Language" = "en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5";
"Content-Type" = "application/json; charset=utf-8";
"User-Agent" = "game/1470 (iPhone; iOS 7.1; Scale/2.00)";
}
request.body=
{
"game":"539e75acadae8fb03900057e",
"to":"533bd7eb5317b88f61000006",
"message":"Ben Fowler is waiting for you to play the game",
"from":"5332b4f5edfc9beb7900004d"
}
2014-06-16 15:58:08.856 game[5961:5607] T restkit.network:RKObjectRequestOperation.m:248 POST 'https://api.myURL.com/api/0_0_1/notify/player' (200 OK / 1 objects) [request=1.6911s mapping=0.0020s total=1.6989s]:
response.headers={
Connection = "keep-alive";
"Content-Length" = 42;
"Content-Type" = "application/json; charset=utf-8";
Date = "Mon, 16 Jun 2014 07:58:09 GMT";
"X-Powered-By" = Express;
}
response.body=
{
"result": 1,
"notify": "871720292"
}
The class being mapped
-(void)WtfGameNotifcationResponse
{
RKObjectMapping *notifyMapping = [RKObjectMapping mappingForClass:[WTFGameNotification class]];
[notifyMapping addAttributeMappingsFromDictionary:
#{
#"result" : #"result",
#"notify" : #"notifyID",
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:notifyMapping
method:RKRequestMethodGET
pathPattern:#"notify/player"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
}
The class in question
#interface WTFGameNotification : NSObject
#property (nonatomic,copy) NSString* to;
#property (nonatomic,copy) NSString* from;
#property (nonatomic,copy) NSString* gameID;
#property (nonatomic,copy) NSString* message;
#property (nonatomic,strong) NSNumber* result;
#property (nonatomic,copy) NSString *notifyID;
+ (WTFGameNotification*)Create;
#end
It seems that if you are trying to map a response from a POST this is the method and syntax one should use.
+ ( void )SendNotification:(GameInfo*)gameInfo withMessage:(NSString*)message forView:(UIViewController*)view
{
WTFGameNotification *_wtfGameNotif = [WTFGameNotification Create];
[_wtfGameNotif setTo:[gameInfo opponentWTFID]];
[_wtfGameNotif setFrom:[PlayerWTFInfo Load]._wtfID];
[_wtfGameNotif setGameID:[gameInfo gameID]];
[_wtfGameNotif setMessage:message];
if ([_wtfGameNotif to] && [_wtfGameNotif gameID])
{
RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:_wtfGameNotif
method:RKRequestMethodPOST
path:nil
parameters:nil];
RFResponse *r1 = [RFResponse new];
operation.targetObject = r1;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
if (r1.result.integerValue != 0)
{
[Utilities FacebookPostWithResult:#{#"fbId": r1.notify}];
}
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
DDLogError(#"POST REQUEST FAILED IN CONFIRMFOTOVC : %#",[error description]);
if (view)
{
[LoadingView PopToRootShutterCloseOnView:view willOpen:YES];
}
}];
[operation start];
}
else
{
DDLogInfo(#"NO PLAYER ID");
}
}
If you are POSTing the object to the server then the response descriptor you have will not match because you link it to a GET with method:RKRequestMethodGET. You need to change that to method:RKRequestMethodPOST.
When using a path pattern of #"notify/player" the base URL should be set to https://api.myURL.com/api/0_0_1/, but it doesn't look like this is an issue for you.
Related
I enabled myLocation and myLocationButton,
but it not showing on my view.
And I try log _mapView.myLocation it's nil.
I need to showing myLocation dot and myLocationButton.
Have some one can help me, thanks!
//
// ViewController.m
//
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>
#import "Reachability.h"
#interface ViewController ()<GMSMapViewDelegate,CLLocationManagerDelegate>
{
CLLocationManager * locationManager;
CLLocation *currentLocations;
Reachability * udnReach;
};
#property (strong,nonatomic) GMSMapView * mapView;
#property (strong,nonatomic) NSDictionary * dic;
#property (nonatomic,strong) NSTimer * updatetimer;
#end
#implementation ViewController {
}
- (void)viewDidLoad {
locationManager =[[CLLocationManager alloc]init];
locationManager.delegate =self;
if ([locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[locationManager requestAlwaysAuthorization];
}
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
[locationManager startUpdatingLocation];
_mapView.delegate = self;
_mapView.myLocationEnabled = YES;
_mapView.settings.myLocationButton = YES;
//Map
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:locationManager.location.coordinate.latitude
longitude:locationManager.location.coordinate.longitude
zoom:16];
_mapView= [GMSMapView mapWithFrame:CGRectZero camera:camera];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(networkStatusChanged:) name:kReachabilityChangedNotification object:nil];
udnReach=[Reachability reachabilityWithHostName:#"google.com"];
// udnReach = [Reachability reachabilityForInternetConnection];
[udnReach startNotifier];
[self updatebike];
self.view = self.mapView;
NSLog(#"User's location: %#", _mapView.myLocation);
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
}
i find to show button and get userlocation
// Rather than setting -myLocationEnabled to YES directly,
// call this method:
- (void)enableMyLocation
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined)
[self requestLocationAuthorization];
else if (status == kCLAuthorizationStatusDenied || status == kCLAuthorizationStatusRestricted)
return; // we weren't allowed to show the user's location so don't enable
else
[self.view setMyLocationEnabled:YES];
}
// Ask the CLLocationManager for location authorization,
// and be sure to retain the manager somewhere on the class
- (void)requestLocationAuthorization
{
_locationAuthorizationManager = [[CLLocationManager alloc] init];
_locationAuthorizationManager.delegate = self;
[_locationAuthorizationManager requestAlwaysAuthorization];
}
// Handle the authorization callback. This is usually
// called on a background thread so go back to main.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status != kCLAuthorizationStatusNotDetermined) {
[self performSelectorOnMainThread:#selector(enableMyLocation) withObject:nil waitUntilDone:[NSThread isMainThread]];
_locationAuthorizationManager.delegate = nil;
_locationAuthorizationManager = nil;
}
}
I use AFNetworking get method, the url is something like :
http://www.hi-pda.com/forum/redirect.php?from=notice&goto=findpost&pid=31089630&ptid=1631932
using chrome I can see the true URL is :
It is in the location .
How can I get the url when using AFNetworking , I tried the following method, it does not work
[
manager GET:threadNotice.URLString
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#",[operation.response allHeaderFields]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}
];
The response is
2015-05-31 00:11:03.349 HiPDA V2[20006:751020] {
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html";
Date = "Sat, 30 May 2015 16:10:59 GMT";
Server = "nginx/1.6.2";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "PHP/5.3.10";
}
no location field,how can I get that? thank you.
I solved the answer used the following method:
AFHTTPRequestOperation *requestOperation=[[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_URLString]]];
[requestOperation setRedirectResponseBlock:^NSURLRequest *(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse) {
if (redirectResponse) {
//this is the redirected url
NSLog(#"%#",request.URL);
}
return request;
}];
[requestOperation start];
I am trying to write some code to have a user enter their username and password and then authenticate against a server using basic HTTP authentication. I can do it using AFNetworking 2 BUT I want to be able to return whether or not the request was successful. The code below works, but how can I refactor it so that I can call the method and then return a BOOL true or false?? It is driving me crazy that I can't do this.
- (void)authenticateWithUserEmail:(NSString *)pUserEmail
withUserPassword:(NSString *)pUserPassword {
NSString *loginURL =
#"https://mydomain/login";
AFHTTPRequestOperationManager *manager =
[AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer
setAuthorizationHeaderFieldWithUsername:pUserEmail
password:pUserPassword];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
AFHTTPRequestOperation *operation = [manager GET:loginURL
parameters:[self jsonDict]
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[operation start];
}
- (IBAction)btnAuthenticate:(id)sender {
[self authenticateWithUserEmail:self.userEmail.text
withUserPassword:self.userPassword.text];
}
Because the network call is performed asynchronously, you can't simply return a BOOL because the method returns as soon as you call [operation start];, at which point the network call hasn't completed. What you need to do is add a block parameter to your method that get's invoked in the completion or failure block of the AFHTTPRequestOperation So your method signature will look like this:
- (void)authenticateWithUserEmail:(NSString *)pUserEmail
withUserPassword:(NSString *)pUserPassword
completion:(void (^)(BOOL success))completionBlock;
In this method, add to your success/failure blocks to invoke your new block parameter. Like so:
AFHTTPRequestOperation *operation = [manager GET:loginURL
parameters:[self jsonDict]
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionBlock) {
completionBlock(YES);
}
NSLog(#"Success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionBlock) {
completionBlock(NO);
}
NSLog(#"Failure");
}];
And your invocation of this method will now look like this:
- (IBAction)btnAuthenticate:(id)sender {
[self authenticateWithUserEmail:self.userEmail.text
withUserPassword:self.userPassword.text
completion:^(BOOL success) {
if (success) {
//login successful, do stuff
} else {
//login failed, do other stuff
}
}];
}
This generally how to handle responding to asynchronous events, since you can't return something that hasn't been determined yet.
First of all, I'm new to objective-c programming so I've probably made some mistakes in my code.
Here's what I've done : I've created a php file with some xml to get values from my MySQL database. Everything goes into a NSArray in objective-C. If I look at the log, everything works fine because it shows my arrays with every MySQL rows and columns like this:
2012-04-02 08:20:14.822 POS[64632:707] (
{
CPU = 0;
TPS = "(null)";
TVQ = "(null)";
consigne = 0;
coutantQuantiteRecue = 0;
description = "";
nom = "";
prixProduit = 0;
quantiteRecue = 0;
stock = 0;
},
{
CPU = 768;
TPS = "(null)";
TVQ = "(null)";
consigne = 0;
coutantQuantiteRecue = 0;
description = "";
nom = hhh;
prixProduit = 0;
quantiteRecue = 0;
stock = 0;
},
2012-04-02 08:20:14.836 POS[64632:707] The number of rows is:2
The problem is that the only thing I get in my TableView is { in each cell like this:
Here's my .h :
#interface InventoryManagement : NSObject<NSApplicationDelegate, NSTableViewDataSource>
{
IBOutlet NSTableView* inventoryTable;
NSArray* m_items;
}
-(int)numberOfRowsInTableView:(NSTableView *)inventoryTable;
-(id)tableView:(NSTableView *)inventoryTable objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)rowIndex;
-(void)dealloc;
#property (retain) NSArray* m_items;
#end
And here's my .m file :
#implementation InventoryManagement
#synthesize m_items;
-(id)init
{
[super init];
NSInteger index = 0;
NSString *urlString = [NSString stringWithFormat:#"http://localhost:8888/php/getProducts.php?index=%d&", index];
m_items = [NSArray arrayWithContentsOfURL:[NSURL URLWithString: urlString]];
NSLog(#"%#", [m_items description]);
[m_items retain];
[inventoryTable reloadData];
return self;
}
-(int)numberOfRowsInTableView:(NSTableView *)inventoryTable
{
NSLog(#"The number of rows in fullResult is:%i", [m_items count]);
return [m_items count];
}
-(id)tableView:(NSTableView *)inventoryTable objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)rowIndex
{
return [m_items objectAtIndex:rowIndex];
}
-(void)dealloc
{
[m_items release];
[super dealloc];
}
#end
My object is well-connected to dataSource and delegate of my TableView. I want those cells to be filled by my database values.
Take a look at Cocoa Bindings for future works. They are great.
Regarding your question: the problem is in the method
-(id)tableView:(NSTableView *)inventoryTable objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)rowIndex
{
return [m_items objectAtIndex:rowIndex];
}
You are returning the whole object, that is:
{
CPU = 768;
TPS = "(null)";
TVQ = "(null)";
consigne = 0;
coutantQuantiteRecue = 0;
description = "";
nom = hhh;
prixProduit = 0;
quantiteRecue = 0;
stock = 0; }
which is a string.
You have to check the tableColumn variable and return only the right information: e.g. quantiteRecue, CPU, etc..
The best way to do this is to create a Model class in ObjectiveC which wraps a row of your db. Then your m_items array will contains your Model class, and you can return the right property without parsing every time the string...
I've noticed some strange behavior in iOS 5: NSSetUncaughtExceptionHandler() doesn't seem to do anything anymore.
I have the following code:
static NSString* documentsDirectory()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
static void handleException(NSException *exception)
{
// Write something to the documents dir
NSString* path = [documentsDirectory() stringByAppendingPathComponent:#"crashlog.txt"];
NSString* str = #"Handled exception";
NSError* err;
if(![str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&err])
{
NSLog(#"Failed to write to file");
}
NSLog(#"Handled exception");
}
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&handleException);
[NSException raise:#"Test" format:#"Testing"];
...
}
The above code works on any device or simulator running 4.x or earlier. However, when I run it on the 5.0 simulator, the exception handler doesn't get called (doesn't write the file to the documents dir, doesn't log, and doesn't trigger if I set a breakpoint inside the handler).
Unfortunately, I don't have a 5.0 device available for testing, so I'm hoping someone could confirm that it's broken on 5.0 so I can file a bug report (or correct me, if there's a problem with my code).
Use iOS 6.0 SDK, build and run it on simulator 5.0! It works!
//////Code:
static NSString* documentsDirectory()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
static void handleException(NSException *exception)
{
// Write something to the documents dir
NSString* path = [documentsDirectory() stringByAppendingPathComponent:#"crashlog.txt"];
NSString* str = #"Handled exception";
NSError* err;
if(![str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&err])
{
NSLog(#"Failed to write to file");
}
NSLog(#"Handled exception");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSSetUncaughtExceptionHandler(&handleException);
[NSException raise:#"Test" format:#"Testing"];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[NSSetUncaughtExceptionHandlerTestViewController alloc] initWithNibName:#"NSSetUncaughtExceptionHandlerTestViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
//////Terminal log:
2012-10-09 20:06:24.726 NSSetUncaughtExceptionHandlerTest[7815:c07] Handled exception
2012-10-09 20:06:24.727 NSSetUncaughtExceptionHandlerTest[7815:c07] *** Terminating app due to uncaught exception 'Test', reason: 'Testing'
*** First throw call stack:
(0x14a4052 0xea4d0a 0x144ca78 0x144c9e9 0x29d7 0x129d6 0x138a6 0x22743 0x231f8 0x16aa9 0x138efa9 0x14781c5 0x13dd022 0x13db90a 0x13dadb4 0x13daccb 0x132a7 0x14a9b 0x28b2 0x27e5)
terminate called throwing an exception(lldb)
I'm seeing the same thing. It works on my iPad, but not in the simulator. If someone confirms on the phone, please feel free to edit this answer to reflect that.