Nested Select Query missing pointer and className -- Parse.com - ios

When I do a query that requests just some selected fields of a pointer, the response that is received does not include the pointer type and class name.
Example :
PFQuery * query = [PFQuery queryWithClassName:#"ClassA"];
[query includeKey:#"column1"]; // This is a pointer with classname : ClassB
[query selectKeys:#[#"column1.subColumn1",#"column1.subColumn2"]];
The result is
"column1": {
"createdAt": "2015-10-29T19:46:17.167Z",
"subColumn1": "Some Value1",
"subColumn2": "Some Value2",
"objectId": "iCK9CpgKAh",
"updatedAt": "2015-11-16T14:30:11.312Z"
},
But, if I don't just select some fields, and include all subcolumns fields, it will work :
PFQuery * query = [PFQuery queryWithClassName:#"ClassA"];
[query includeKey:#"column1"]; // This will select all fields inside column1
Result :
"column1": {
"__type": "Pointer",
"className": "ClassB",
"createdAt": "2015-10-29T19:46:17.167Z",
"subColumn1": "Some Value1",
"subColumn2": "Some Value2",
"subColumn3": "Some Value3",
"objectId": "iCK9CpgKAh",
"updatedAt": "2015-11-16T14:30:11.312Z"
},
This create a problem when we use a PFSubclassing, because the pointer column is not treated as a pointer, but as a NSDictionary.
For example :
PFClassA and PFClassB are parse subclassess.
#interface PFClassB : PFObject<PFSubclassing>
#property (copy) NSString * subColumn1;
#property (copy) NSString * subColumn2;
#property (copy) NSString * subColumn2;
#end
#interface PFClassA : PFObject<PFSubclassing>
#property (strong) PFClassB * column1;
#end
When we do a query that just select 2 fields of the PFClassB like the above query,
the result of column1 will be a dictionary, and not a PFClassB.
Is there a workaround?
Thanks.

Related

Restkit fails to use appropriate Mapping

I am using Restkit 0.26.0 to map JSON with multiple layers and this key path causes trouble:
productColorImages: [
{
id: 10,
productId: "232",
color: "green",
url: "exampleURL.com"
},
{
id: 11,
productId: "232",
color: "red",
url: "exampleURL.com"
},
{
id: 12,
productId: "232",
color: "blue",
url: "exampleURL.com"
}
],
My mapping
RKObjectMapping *transferProductColorImageMapping = [RKObjectMapping mappingForClass:[TransferProductColorImage class]];
[transferProductColorImageMapping addAttributeMappingsFromDictionary:#{ #"identifier" : #"id",
#"URL" : #"URL",
#"productId" : #"productId",
#"color" : #"color"
[getProductPageMapping addRelationshipMappingWithSourceKeyPath:#"productColorImages" mapping:transferProductColorImageMapping];
The destination class
#interface TransferProductColorImage : NSObject
#property (nonatomic) NSNumber * identifier; // Mapps to id ;int 64
#property (nonatomic) NSString * URL;
#property (nonatomic) NSString * productId;
#property (nonatomic) NSString * color;
The problem is that the resulting Object is of the right class but the properties are not filled.
I searched in the logs and found this:
2016-05-30 17:42:24.007 thebrandsapp[20697:7047455] T restkit.object_mapping:RKMappingOperation.m:1173 Performing mapping operation: <RKMappingOperation 0x7f9e3b9c11e0> for 'TransferProductColorImage' object. Mapping values from object {
color = green;
id = 10;
productId = 232;
url = "exampleURL.com";
} to object <TransferProductColorImage: 0x7f9e3b846d60> with object mapping (null)
On the Model Object the productColorImages is a NSArray:
#property (nonatomic) NSArray <TransferProductColorImage *> * productColorImages;
This is odd because. How does Restkit know what mapping to use if the mapping is null. Is there any reason why the object mapping could be set to null?
Update: I found that the identifier and the color property were mapped correctly it is, the identifier and the url are not mapped correctly.
I changed the URL property to be lowercase: "url" and mapped it exactly like I did before and it worked. It seems like the the all-caps property name threw RestKit of.
I swooped identifier and id, now they map correctly as well.

Filter an array with predicate in iOS

I have an array of JSONModel objects. The JSONModel object looks like this
#interface ProductModel : JSONModel
#property(nonatomic, strong) NSString *name;
#property(nonatomic, strong) NSString *price;
#property(nonatomic, strong) NSArray *productCategories;
#end
Inside the productCategory model I have this
#interface ProductCategoryModel : JSONModel
#property (nonatomic,assign) NSString *id;
#end
The json looks like this
{
"productCount":"129",
"products": [
{
"name": "Art attack",
"price": "$19.99",
"prouctCategories":[
{ "id": "50" }
{ "id": "10" }
]
}
I have to filter the array checking the id property of a productCategory in the array productCategories.One product can have multiple categories. I need to get for example the list of products with the id : 10.
I want to get that list using filteredArrayUsingPredicate method of an NSArray but I cannot find the right predicate format to get this. Is it possible to do that using predicate.
I tried this predicate but I didn't get anything
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# == '%#"', #"id", #"50"];
NSPredicate documentation is pretty clear about building this kind of queries. You can use ANY clause to apply filter on many-to-many relationships to get the products whose any of the category's ID is 10.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(ANY productCategories.id == '10')"];
NSArray *filteredProducts = [products filteredArrayUsingPredicate:predicate];
To simplify the problem change the json to look like this:
{
"productCount":"129",
"products": [
{
"name": "Art attack",
"price": "$19.99",
"productCategories":["50","10"]
}
So you can use such predicate:
[NSPredicate predicateWithFormat:#"productCategories CONTAINS '10')"]
You can use NSPredicate as your json is like
{
"productCount":"129",
"products": [
{
"name": "Art attack",
"price": "$19.99",
"prouctCategories":[
{ "id": "50" }
{ "id": "10" }
]
}
then you may check it with this:
NSArray *arrFiltered = [arrProducts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(self.prouctCategories.id == '10')"]];
Or you may also change your json format to make things more easier like
{
"productCount":"129",
"products": [
{
"name": "Art attack",
"price": "$19.99",
"prouctCategories":[
{ "id": 50,10,20 }
]
}
So you may filtered id like this
NSArray *arrFiltered = [arrProducts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(self.prouctCategories.%K CONTAINS '10')", 'id']];
Hope it will help you. :)

How to create model classes using JSONModel?

I am trying to create Model Class by using JSONModel.My json Dictionary after using NSJSONSerialization looks like below.
{
apiStatus = {
message = SUCCESS;
success = 1;
};
boardingPoints = "<null>";
inventoryType = 0;
seats = (
{
ac = 0;
available = 1;
bookedBy = "<null>";
commission = "<null>";
fare = 1200;
},
{
ac = 0;
available = 1;
bookedBy = "<null>";
commission = "<null>";
fare = 1200;
},
);
}
The JSON looks like this:
{"boardingPoints":null,"inventoryType":0,"apiStatus":{"success":true,"message":"‌​SUCCESS"},"seats":[{"fare":1200,"commission":null,"bookedBy":null,"ac":false,"ava‌​ilable":true},{"fare":1200,"commission":null,"bookedBy":null,"ac":false,"availabl‌​e":true},]}
I have a model class like this :-
#interface Seat : JSONModel
#property (nonatomic,strong)NSString *ac;
#property (nonatomic,strong)NSString *available;
#property(nonatomic,strong)NSString *bookedBy;
#property(nonatomic,strong)NSString *comission;
#property(nonatomic)NSNumber * fare;
For mapping keys I have done like this:-
+(JSONKeyMapper*)keyMapper {
return [[JSONKeyMapper alloc] initWithDictionary:#{#"ac":#"ac",
#"available":#"available",
#"bookedBy":#"bookedBy",
#"commission":#"commission",
#"fare":#"fare", }];
}
However when I try to use this model I get the following error:
[JSONModel.m:252] Incoming data was invalid [Seat initWithDictionary:]. Keys missing: {(
bookedBy,
comission,
available,
ac,
fare,
)}
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
I am using it like this:
//Using JSON Model.
NSError *jsonError;
seat = [[Seat alloc]initWithDictionary:jsonDictionary error:&jsonError];
jsonArray = #[seat.ac,seat.available,seat.bookedBy,seat.comission,seat.fare];
NSLog(#"JSON Model Array : %#", jsonArray);
How to use it correctly?
First of all, you don't need to override +(JSONKeyMapper*)keyMapper if your property names matches with the field names. Try putting the optional keyword for fields that can be null.
#interface Seat : JSONModel
#protocol Seat;
#property (nonatomic,strong)NSString *ac;
#property (nonatomic,strong)NSString<Optional> *available;
#property(nonatomic,strong)NSString<Optional> *bookedBy;
#property(nonatomic,strong)NSString *comission;
#property(nonatomic)NSNumber * fare;
#end
Taking this a step further, you can do cascading in your top class like this:
//Result.h
#import "Seat.h"
#import "APIStatus.h"
#interface Result: JSONModel
#property(nonatomic,strong) APIStatus *apiStatus;
#property(nonatomic,strong) NSString<Optional> *boardingPoints;
#property(nonatomic,strong) NSArray<Seat> *seats;
#property(nonatomic,strong) NSNumber *boardingPoints;
#end
//APIStatus.h
#interface APIStatus: JSONModel
#property(nonatomic,strong) NSString *message;
#property(nonatomic,strong) NSNumber *success;
#end
EDIT: This way you only need to init the Result model with JSONModel, all the intermediary classes will be created automatically. You may need to play around with the property types. JSONModel's github page offers good amount of explanations if you need a reference.
You need to correct your JSON string - remove the comma after the last entry of seats.
I think you may have to indicate you are working with nested models here i.e. seats are a nested model of your top level model which at this point is anonymous but really denoted by the top level { } braces.
Have a look at this - it describes how to set things up with nested models.
JSONModel tutorial covering nested models
Here is your corrected JSON string:
{
"boardingPoints": null,
"inventoryType": 0,
"apiStatus": {
"success": true,
"message": "‌​SUCCESS"
},
"seats": [
{
"fare": 1200,
"commission": null,
"bookedBy": null,
"ac": false,
"ava‌​ilable": true
},
{
"fare": 1200,
"commission": null,
"bookedBy": null,
"ac": false,
"availabl‌​e": true
}
]}

RKObjectMapping connections

I have neхt response:
{
"orders": [
{
"date": "2013-11-18T13:00:39.000Z",
"state": "new",
"id": 11,
"order_item_ids": [
27,
28
]
}
],
"order_items": [
{
"count": 2,
"id": 27,
"item_id": 1,
"order_id": 11
},
{
"count": 1,
"id": 28,
"item_id": 2,
"order_id": 11
}
]
}
And next object I want to map it:
#interface Order : NSObject
#property (nonatomic, strong) NSString* state;
#property (nonatomic, strong) NSMutableArray* orderItems;
#property (nonatomic, strong) NSDate* visitDate;
#end
orderItems should be array of:
#interface OrderItem : NSObject
#property (nonatomic) NSUInteger ID;
#property (nonatomic) NSUInteger itemID;
#property (nonatomic) NSUInteger count;
#end
In case of RKEntityMapping I should use addConnectionForRelationship to map order_item_ids to orderItems array via order_items response. But what should I do to do to connect it in case of RKObjectMapping? Off course I can map both orders and orderItems with separate response descriptors and than parse it, but I want to make RestKit do it for me. Another idea is to use CoreData and RKEntityMapping but I'm not sure that I want in this case, it will be overkill in this case.
You can't have it done automatically with RKObjectMapping because you can't index into both arrays in any way. The entity mapping only works because you can use foreign key mapping after both mappings have been performed. You can duplicate this by using multiple response descriptors and mappings and then combining the contents of the mapping result.

Parsing JSON in iOS, inner dictionaries

I am new to JSON and iOS, I have some json data that I want to load into an array,
This is the json data
{
"items": [
{
"name": "abc",
"description": "cheeseburger",
},
{
"name": "def",
"description": "ostrichburger",
},
{
"name": "zxc",
"description": "sh1tjustgotreal",
},
{
"name": "scfs",
"description": "mylifeforaiur",
}
]
}
Now I keep on getting dictionaries with dictionaries? Why is that?
On another note, If I can modify the structure of this json cos I really just want to access the inner nodes ( abc, def ) what would I change in it to make it simpler for me and others to use it? Can I get rid of the "items" node?
When the data on the sender's end is structured as a collection of named fields, you get back a dictionary for each group of named fields. In this particular case, it looks like the outermost object has one field, which is a collection (i.e. a list or an array) of objects that each have a name and description. In other words, the sender sends you something like this:
#interface Item
#property (readwrite, copy) NSString* name;
#property (readwrite, copy) NSString* description;
#end
#interface MyObject
// This array contains objects of type Item
#property (readwrite) NSArray *items;
#end

Resources