I use
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
and this sends out the call to the server when having an array in the format:
payments[]
payments[][email]=0&
payments[][category]=&
payments[][email]=1&
payments[][category]=&
I need the indexes for the server like.
payments[]
payments[0][email]=0&
payments[0][category]=&
payments[1][email]=1&
payments[1][category]=&
How can I achieve that?
Thanks.
AFHTTPRequestSerializer has a method setQueryStringSerializationWithBlock which allows you to provide your own block for serializing the parameters.
Unfortunately, the internal AF* functions for serialization are private, but you can copy them and make a small modification in these lines to add the indexes.
To set your own serialization block:
[serializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, id parameters, NSError *__autoreleasing *error) {
return ZAFQueryStringFromParametersWithEncoding(parameters, serializer.stringEncoding);
}];
Including the code, where the AFNetworking functions have been copied and prefixed with a Z to ZAF:
static NSString * const kAFCharactersToBeEscapedInQueryString = #":/?&=;+!##$()',*";
static NSString * AFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
static NSString * const kAFCharactersToLeaveUnescapedInQueryStringPairKey = #"[].";
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding));
}
static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding));
}
#pragma mark -
#interface ZAFQueryStringPair : NSObject
#property (readwrite, nonatomic, strong) id field;
#property (readwrite, nonatomic, strong) id value;
- (id)initWithField:(id)field value:(id)value;
- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding;
#end
#implementation ZAFQueryStringPair
- (id)initWithField:(id)field value:(id)value {
self = [super init];
if (!self) {
return nil;
}
self.field = field;
self.value = value;
return self;
}
- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding {
if (!self.value || [self.value isEqual:[NSNull null]]) {
return AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding);
} else {
return [NSString stringWithFormat:#"%#=%#", AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)];
}
}
#end
#pragma mark -
static NSArray * ZAFQueryStringPairsFromDictionary(NSDictionary *dictionary);
static NSArray * ZAFQueryStringPairsFromKeyAndValue(NSString *key, id value);
static NSString * ZAFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (ZAFQueryStringPair *pair in ZAFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]];
}
return [mutablePairs componentsJoinedByString:#"&"];
}
NSArray * ZAFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return ZAFQueryStringPairsFromKeyAndValue(nil, dictionary);
}
NSArray * ZAFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"description" ascending:YES selector:#selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
// Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:#[ sortDescriptor ]]) {
id nestedValue = [dictionary objectForKey:nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:ZAFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:#"%#[%#]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
NSInteger idx = 0;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:ZAFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:#"%#[%ld]", key, idx++], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:#[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:ZAFQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[ZAFQueryStringPair alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}
Related
am new to iOS, Getting issue with displaying data from below service data
[{
"Name": Rahul,
"FatherName": Ravinder,
"Designation": Engineering,
"Profession": Software Eng,
"Height": "5 ft 3 in",
"Weight": "134.5 lbs"
}]
below is the code what i have tried. Please help me to find the issue. Thanks In Advance.
NameDetails.m
---------------
- (void)viewDidLoad {
[super viewDidLoad];
[self callService:[appDelegate.signUpdata objectForKey:#"id"]];
}
-(void)callService:(NSString *)userid
{
[Utility showIndicator:nil view1:self.view];
JsonServicePostData = [[JsonServiceCls alloc] init];
JsonServicePostData.delegate = self;
[JsonServicePostData Getdata:userid];
}
-(void)DidFinishWebServicesPostData
{
[Utility hideIndicator];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
_txtName.text=[dict objectForKey:#"Name"];
_txtFName.text=[dict objectForKey:#"FatherName"];
_txtDesg.text=[dict objectForKey:#"Designation"];
_txtprof.text=[dict objectForKey:#"Profession"];
_txtHeight.text=[dict objectForKey:#"Height"];
_txtWeight.text=[dict objectForKey:#"Weight"];
}
}
+(void)makeHttpGETresponceParsingwithSerVer:(NSString *)strServer withCallBack:(void(^)(NSDictionary *dicArr,NSError *error))handler
{
NSURL *urlServer = [NSURL URLWithString:strServer];
NSURLRequest *request = [NSURLRequest requestWithURL:urlServer];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
handler(res,error);
}];
[postDataTask resume];
}
then call your method In viewDidLoad...
[RestClient makeHttpGETresponceParsingwithSerVer:#"YOUR_URL" withCallBack:^(NSDictionary *responceDic, NSError *error) {
_txtName.text =[responceDic objectForKey:#"Name"];
_txtFName.text =[responceDic objectForKey:#"FatherName"];
_txtDesg.text =[responceDic objectForKey:#"Designation"];
_txtprof.text =[responceDic objectForKey:#"Profession"];
_txtHeight.text =[responceDic objectForKey:#"Height"];
_txtWeight.text =[responceDic objectForKey:#"Weight"];
}];
// RestClient is the class name as it is a class method, You can use instance method.
Hi The better approach is for this kind of API call activity you have to go with AFNetworking - https://github.com/AFNetworking/AFNetworking
Its Pretty simple and more powerful. Once you get the json response you have to go for Model Approach.
#import <UIKit/UIKit.h>
#interface NameDetails : NSObject
#property (nonatomic, strong) NSString * designation;
#property (nonatomic, strong) NSString * fatherName;
#property (nonatomic, strong) NSString * height;
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSString * profession;
#property (nonatomic, strong) NSString * weight;
-(instancetype)initWithDictionary:(NSDictionary *)dictionary;
-(NSDictionary *)toDictionary;
#end
#import "RootClass.h"
NSString *const kRootClassDesignation = #"Designation";
NSString *const kRootClassFatherName = #"FatherName";
NSString *const kRootClassHeight = #"Height";
NSString *const kRootClassName = #"Name";
NSString *const kRootClassProfession = #"Profession";
NSString *const kRootClassWeight = #"Weight";
#interface RootClass ()
#end
#implementation RootClass
/**
* Instantiate the instance using the passed dictionary values to set the properties values
*/
-(instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if(![dictionary[kRootClassDesignation] isKindOfClass:[NSNull class]]){
self.designation = dictionary[kRootClassDesignation];
}
if(![dictionary[kRootClassFatherName] isKindOfClass:[NSNull class]]){
self.fatherName = dictionary[kRootClassFatherName];
}
if(![dictionary[kRootClassHeight] isKindOfClass:[NSNull class]]){
self.height = dictionary[kRootClassHeight];
}
if(![dictionary[kRootClassName] isKindOfClass:[NSNull class]]){
self.name = dictionary[kRootClassName];
}
if(![dictionary[kRootClassProfession] isKindOfClass:[NSNull class]]){
self.profession = dictionary[kRootClassProfession];
}
if(![dictionary[kRootClassWeight] isKindOfClass:[NSNull class]]){
self.weight = dictionary[kRootClassWeight];
}
return self;
}
/**
* Returns all the available property values in the form of NSDictionary object where the key is the approperiate json key and the value is the value of the corresponding property
*/
-(NSDictionary *)toDictionary
{
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
if(self.designation != nil){
dictionary[kRootClassDesignation] = self.designation;
}
if(self.fatherName != nil){
dictionary[kRootClassFatherName] = self.fatherName;
}
if(self.height != nil){
dictionary[kRootClassHeight] = self.height;
}
if(self.name != nil){
dictionary[kRootClassName] = self.name;
}
if(self.profession != nil){
dictionary[kRootClassProfession] = self.profession;
}
if(self.weight != nil){
dictionary[kRootClassWeight] = self.weight;
}
return dictionary;
}
The above one is Model Class.
Your JSON look like a array. So you need to iterate the Dictionary values on it. Other than that you may pass it directly.
Now in your ViewController class initiate the mutable array
and pass the response like
NSArray *arrayData = ResponseFromAFNETWORKING
for (NSDictionary *data in arrayData) {
NameDetails *modelFeed = [[NameDetails alloc] initFromDictinary:data]
[self.YourMutableDictionary addObject:modelFeed]
}
self.updateDisplay:self.YourMutableDictionary[0] // If not array No iteration, you can prepare the model and pass it directly
----------------------------------------
- (void)updateDisplay:(NameDetails *)feed {
_txtName.text =feed.Name;
_txtFName.text =feed.FatherName;
_txtDesg.text =feed.Designation;
_txtprof.text =feed.Profession;
_txtHeight.text =feed.Height;
_txtWeight.text =feed.Weight;
}
Hope this will help. This is a robust and elastic approach, thread safe mechanism too
I have 100 key and value in nsmutabledictornary and i want to check that any value have null or not. Do you have any short function or technique?
I don't want to multiple line code like check every key and value. Your answer would be appreciated.
This code will give you the set of keys which have (non)null values. You can't store actual nil values in a dictionary, so [NSNull null] is assumed. The predicate is trivially alterable to any other condition.
NSDictionary *d = #{ #"a" : #"1", #"b" : [NSNull null] };
NSSet *nullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]];
}];
NSSet *nonnullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]] == NO;
}];
From here, you can use the keys to generate a corresponding dictionary, if needed.
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([nonnullKeys contains:key]) {
nonNullDict[key] = obj;
}
}];
If you don't need a separate list of keys, and just need the filtered dictionary, skip the first step and modify the second part to read as follows:
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSNull null]] == NO) {
nonNullDict[key] = obj;
}
}];
Write category on NSDictionary it will provide you null free dictionary. Here is the category I have written for myself.
code for .h file (interface)
#import <Foundation/Foundation.h>
#interface NSDictionary (CheckNull)
{
}
- (NSDictionary *)nullFreeDictionary;
#end
Code for .m file. (implementation)
#import "NSDictionary+CheckNull.h"
#implementation NSDictionary (CheckNull)
- (NSDictionary *) nullFreeDictionary
{
NSMutableDictionary *tempDictionary = [self mutableCopy];
for (NSString *key in tempDictionary.allKeys) {
NSString *value = [tempDictionary valueForKey:key];
if ([value isKindOfClass:[NSString class]]) {
if (value == (id)[NSNull null] || value == nil || value.length == 0) {
[tempDictionary setValue:#"" forKey:key];
}
}
}
return tempDictionary;
}
Call null free method on your dictionary using above category.
NSDictionary *dict = [dict nullFreeDictionary];
//To remove NULL from Dictionary
-(NSMutableDictionary *)removeNullFromDictionary : (NSMutableDictionary *)dict
{
// if (![dict isKindOfClass:[NSMutableDictionary class]])
// {
// }
dict = [[NSMutableDictionary alloc] initWithDictionary:dict];
for (NSString * key in [dict allKeys])
{
if ([dict[key] isKindOfClass:[NSNull class]])
{
[dict setValue:#"" forKey:key];
}
else if ([dict[key] isKindOfClass:[NSMutableDictionary class]]||[dict[key] isKindOfClass:[NSDictionary class]])
{
dict[key] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:dict[key]]];
}
else if ([dict[key] isKindOfClass:[NSMutableArray class]]||[dict[key] isKindOfClass:[NSArray class]])
{
dict[key] = [self removeNullFromArray:[NSMutableArray arrayWithArray:dict[key]]];
}
}
return dict;
}
//To remove NULL from Array
-(NSMutableArray *)removeNullFromArray : (NSMutableArray *)arr
{
// if (![arr respondsToSelector:#selector(addObject:)])
// {
// arr = [[NSMutableArray alloc] initWithArray:arr];
// }
arr = [[NSMutableArray alloc] initWithArray:arr];
for (int cnt = 0; cnt<[arr count]; cnt++)
{
if ([arr[cnt] isKindOfClass:[NSNull class]])
{
arr[cnt] = #"";
}
else if ([arr[cnt] isKindOfClass:[NSMutableDictionary class]]||[arr[cnt] isKindOfClass:[NSDictionary class]])
{
arr[cnt] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:arr[cnt]]];
}
else if ([arr[cnt] isKindOfClass:[NSMutableArray class]]||[arr[cnt] isKindOfClass:[NSArray class]])
{
arr[cnt] = [self removeNullFromArray:[NSMutableArray arrayWithArray:arr[cnt]]];
}
}
return arr;
}
I have a Array of custom objects with object having following properties optionID,OptionText. I want to get comma separated string for the optionID property. What would be the best approach to do this in iOS SDK.
for example NSString CommaSeperted = #"1,3,5" etc.
Category to NSArray:
#implementation NSArray(CustomAdditions)
- (NSString *)commaSeparatedStringWithSelector:(SEL)aSelector
{
NSMutableArray *objects = [NSMutableArray array];
for (id obj in self)
{
if ([obj respondsToSelector:aSelector]) {
IMP method = [obj methodForSelector:aSelector];
id (*func)(id, SEL) = (void *)method;
id customObj = func(obj, aSelector);
if (customObj && [customObj isKindOfClass:[NSString class]]) {
[objects addObject:customObj];
}
}
}
return [objects componentsJoinedByString:#","];
}
#end
Example:
#implementation NSDictionary(Test)
- (NSString*)optionID
{
return [self objectForKey:#"optionID"];
}
- (NSString*)OptionText
{
return [self objectForKey:#"OptionText"];
}
#end
NSArray *customObjects = #[#{#"optionID": #"id1", #"OptionText": #"text1" }, #{#"optionID" : #"id2", #"OptionText": #"text2"}];//List of Your custom objects
NSString *commaSeparatedOptionIDs = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"optionID")];
NSString *commaSeparatedOptionTexts = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"OptionText")];
Try this
NSString *commaSeparatedStringOfID = #"";
for (CustomClass *object in yourArray){
commaSeparatedStringOfID = [commaSeparatedStringOfID stringByAppendingString:[NSString stringWithFormat:#"%#,"]];
}
// removing last comma
commaSeparatedStringOfID = [commaSeparatedStringOfID substringToIndex:[commaSeparatedStringOfID length]-1];
commaSeparatedStringOfID will be your required string.
so I have an object with several properties that I want to add to coredata however I'm using the Mantle framework that I am not too familiar with.
My Object(.h):
#import <Foundation/Foundation.h>
#import "RTModel.h"
#import CoreLocation;
#class RTPhoto;
#class RTContact;
#class RTUser;
#interface MyInteraction : RTModel <NSCopying, MTLJSONSerializing>
+ (NSManagedObject *)managedObjectWithIdentifier:(NSNumber *)identifier;
- (NSManagedObject *)managedObject;
#property (nonatomic, strong) NSNumber *latitude;
#property (nonatomic, strong) NSNumber *longitude;
#property (strong, nonatomic) RTUser *user;
#property (nonatomic, strong) NSNumber *createdByID;
#property (nonatomic, copy) NSString *createdByLabel;
#property (nonatomic, copy) NSString *interactedWithLabel;
#property (strong, nonatomic) NSString *publicShareURLString;
#property (nonatomic, strong) NSSet *photos;
- (void)addPhotosObject:(RTPhoto *)photo;
#end
My Object(.m):
#import "OUTInteraction.h"
#import "RTComment.h"
#import "RTPhoto.h"
#import "RTUser.h"
#import "RTContact.h"
#import "OUTCoreDataController.h"
#import "OUTInteractionsController.h"
#interface MyInteraction () <UIActionSheetDelegate>
#end
#implementation MyInteraction
#synthesize identifier = _identifier;
#synthesize createdAt = _createdAt;
#synthesize updatedAt = _updatedAt;
- (void)deleteWithCompletion:(void (^)(NSError *))completion
{
NSManagedObject *managedObject = [self managedObject];
if (!managedObject) {
completion(nil);
};
[[[MyCoreDataController sharedController] persistenceController] deleteObject:managedObject
saveContextAndWait:YES
completion:^(NSError *error) {
completion(error);
}];
}
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return [[super JSONKeyPathsByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary: #{
#"createdByID" : #"created_by_id",
#"createdByLabel" : #"created_by_label",
#"interactedWithLabel" : #"interacted_with_label",
#"interactionType" : #"interaction_type",
#"latitude" : #"latitude",
#"longitude" : #"longitude",
#"formID" : #"form_id",
#"formEntries" : #"form_entries",
#"interactedWithCity" : #"interacted_with_city",
#"interactedWithRegion" : #"interacted_with_region",
#"publicShareURLString" : #"share_url",
#"photos" : #"images"
}];
}
#pragma mark - Photos
- (void)addPhotosObject:(RTPhoto *)photo
{
if (!photo) return;
NSMutableSet *mutablePhotos = [NSMutableSet setWithSet:self.photos];
[mutablePhotos addObject:photo];
self.photos = [mutablePhotos copy];
}
- (BOOL)hasPhotoToDisplay
{
if (!self.photos) return NO;
if ([[self.photos allObjects] count] > 0) return YES;
return NO;
}
#pragma mark - JSON Transformers
/// #note used by Mantle
+ (NSValueTransformer *)photosJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTPhoto *item = [MTLJSONAdapter modelOfClass:[RTPhoto class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
NSLog(#"mutable set");
return mutableSet;
} reverseBlock:^id(NSSet *set) {
NSLog(#"all objects");
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)commentsJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTComment *item = [MTLJSONAdapter modelOfClass:[RTComment class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
return mutableSet;
} reverseBlock:^id(NSSet *set) {
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)contactsJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTComment *item = [MTLJSONAdapter modelOfClass:[RTContact class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
return mutableSet;
} reverseBlock:^id(NSSet *set) {
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)formEntriesJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *entryDictionaries) {
NSMutableSet *set = [NSMutableSet set];
[entryDictionaries enumerateObjectsUsingBlock:^(NSDictionary *entryDict, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTInteractionFormEntry *entry = [MTLJSONAdapter modelOfClass:[RTInteractionFormEntry class]
fromJSONDictionary:entryDict
error:&error];
[set addObject:entry];
}];
return set;
} reverseBlock:^id(NSSet *set) {
NSMutableArray *array = [NSMutableArray array];
[set enumerateObjectsUsingBlock:^(RTInteractionFormEntry *entry, BOOL *stop) {
[array addObject:[entry jsonDictionary]];
}];
return array;
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)userJSONTransformer
{
return [MTLValueTransformer mtl_JSONDictionaryTransformerWithModelClass:[RTUser class]];
}
/// #note used by Mantle
+ (NSValueTransformer *)interactionTypeJSONTransformer
{
return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:#{
#"email" : #(kRTInteractionTypeEmail),
#"check_in" : #(kRTInteractionTypeCheckIn),
#"note" : #(kRTInteractionTypeNote),
#"meeting" : #(kRTInteractionTypeMeeting)
}];
}
#pragma mark - Core Data
+ (NSString *)managedObjectEntityName
{
return #"Interaction";
}
+ (NSSet *)propertyKeysForManagedObjectUniquing
{
return [NSSet setWithArray:#[#"identifier"]];
}
+ (NSDictionary *)managedObjectKeysByPropertyKey
{
return [[super managedObjectKeysByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary:#{
#"metadata" : [NSNull null],
#"identifier" : #"interactionIdentifier",
}];
}
+ (NSDictionary *)relationshipModelClassesByPropertyKey
{
return [[super relationshipModelClassesByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary:#{
#"comments" : [RTComment class],
#"formEntries" : [RTInteractionFormEntry class],
#"photos" : [RTPhoto class],
#"contacts" : [RTContact class],
#"user" : [RTUser class]
}];
}
#pragma mark - Actions
- (void)delete
{
[[MyInteractionsController controller] deleteInteraction:self
success:^{
} failure:^(NSError *error) {
DDLogError([error description], nil);
}];
}
+ (NSManagedObject *)managedObjectWithIdentifier:(NSNumber *)identifier
{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[MyInteraction managedObjectEntityName]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"interactionIdentifier == %#", identifier];
fetchRequest.fetchLimit = 1;
NSManagedObjectContext *managedObjectContext = [[MyCoreDataController sharedController] managedObjectContext];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSLog(#"Results: %#", results);
if (error) {
DDLogError(#"Error fetching managed object: %#", [error description]);
}
return [results firstObject];
}
- (NSManagedObject *)managedObject
{
return [MyInteraction managedObjectWithIdentifier:self.identifier];
}
- (void)mergeValuesForKeysFromManagedObject:(NSManagedObject *)managedObject
{
if ([managedObject valueForKey:#"photos"]) {
NSMutableSet *combinedPhotos = [NSMutableSet setWithSet:self.photos];
for (NSManagedObject *photoManagedObject in [managedObject valueForKey:#"photos"]) {
RTPhoto *photo = [MTLManagedObjectAdapter modelOfClass:[RTPhoto class]
fromManagedObject:photoManagedObject
error:nil];
if (photo.identifier || photo.localImageData || photo.imageDataPendingUpload) {
[combinedPhotos addObject:photo];
}
}
self.photos = [combinedPhotos copy];
}
}
#end
Basically the problem I'm having when adding the whole object to CoreData
via Mantle is that everything gets added except when it reaches the photos property which is a NSSet it only adds one of the objects, usually the last one.
Here is when the object is added to the context using Mantle(in another file):
[MTLManagedObjectAdapter managedObjectFromModel:interaction
insertingIntoContext:self.context
error:&coreDataError];
If someone has any clue as to why there is only one photos object being added under the "photos" key. I'm unfamiliar with how mantle handles toMany relationships and how to get all of the children added. Thanks
I need receive http-multipart responses from web service. The multipart response with pairs of JSON and image.
How to handle response in two parts (NSDictionary for JSON and NSData for image)?
Thanks in advance!
[UPDATE]
I wrote a category for NSData. Code below:
NSData+MultipartResponses.h
#import <Foundation/Foundation.h>
#interface NSData (MultipartResponses)
- (NSArray *)multipartArray;
- (NSDictionary *)multipartDictionary;
#end
NSData+MultipartResponses.m
#import "NSData+MultipartResponses.h"
#implementation NSData (MultipartResponses)
static NSMutableDictionary *parseHeaders(const char *headers)
{
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
int max=strlen(headers);
int start=0;
int cursor=0;
while(cursor<max)
{
while((headers[cursor]!=':')&&(headers[cursor]!='='))
{
cursor++;
}
NSString *key=[[NSString alloc] initWithBytes:(headers+start) length:(cursor-start) encoding:NSASCIIStringEncoding];
cursor++;
while(headers[cursor]==' ')
{
cursor++;
}
start=cursor;
while(headers[cursor]&&(headers[cursor]!=';')&&((headers[cursor]!=13)||(headers[cursor+1]!=10)))
{
cursor++;
}
NSString *value;
if((headers[start]=='"')&&(headers[cursor-1]=='"'))
{
value=[[NSString alloc] initWithBytes:(headers+start+1) length:(cursor-start-2) encoding:NSASCIIStringEncoding];
}
else
{
value=[[NSString alloc] initWithBytes:(headers+start) length:(cursor-start) encoding:NSASCIIStringEncoding];
}
[dict setObject:value forKey:key];
if(headers[cursor]==';')
{
cursor++;
}
else
{
cursor+=2;
}
while(headers[cursor]==' ')
{
cursor++;
}
start=cursor;
}
return dict;
}
- (NSDictionary *)multipartDictionaryWithBoundary:(NSString *)boundary
{
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
const char *bytes=(const char *)[self bytes];
const char *pattern=[boundary cStringUsingEncoding:NSUTF8StringEncoding];
int cursor=0;
int start=0;
int max=[self length];
int keyNo=0;
while(cursor<max)
{
if(bytes[cursor]==pattern[0])
{
int i;
int patternLength=strlen(pattern);
BOOL match=YES;
for(i=0; i<patternLength; i++)
{
if(bytes[cursor+i]!=pattern[i])
{
match=NO;
break;
}
}
if(match)
{
if(start!=0)
{
int startOfHeaders=start+2;
int cursor2=startOfHeaders;
while((bytes[cursor2]!=(char)0x0d)||(bytes[cursor2+1]!=(char)0x0a)||(bytes[cursor2+2]!=(char)0x0d)||(bytes[cursor2+3]!=(char)0x0a))
{
cursor2++;
if(cursor2+4==max)
{
break;
}
}
if(cursor2+4==max)
{
break;
}
else
{
int lengthOfHeaders=cursor2-startOfHeaders;
char *headers=(char *)malloc((lengthOfHeaders+1)*sizeof(char));
strncpy(headers, bytes+startOfHeaders, lengthOfHeaders);
headers[lengthOfHeaders]=0;
NSMutableDictionary *item=parseHeaders(headers);
int startOfData=cursor2+4;
int lengthOfData=cursor-startOfData-2;
if(([item valueForKey:#"Content-Type"]==nil)&&([item valueForKey:#"filename"]==nil))
{
NSString *string=[[NSString alloc] initWithBytes:(bytes+startOfData) length:lengthOfData encoding:NSUTF8StringEncoding];
keyNo++;
[dict setObject:string forKey:[NSString stringWithFormat:#"%d", keyNo]];
}
else
{
NSData *data=[NSData dataWithBytes:(bytes+startOfData) length:lengthOfData];
[item setObject:data forKey:#"data"];
keyNo++;
[dict setObject:item forKey:[NSString stringWithFormat:#"%d", keyNo]];
}
}
}
cursor=cursor+patternLength-1;
start=cursor+1;
}
}
cursor++;
}
return dict;
}
- (NSArray *)multipartArray
{
NSDictionary *dict=[self multipartDictionary];
NSArray *keys=[[dict allKeys] sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
NSMutableArray *array=[NSMutableArray array];
for(NSString *key in keys)
{
[array addObject:dict[key]];
}
return array;
}
- (NSDictionary *)multipartDictionary
{
const char *bytes=(const char *)[self bytes];
int cursor=0;
int max=[self length];
while(cursor<max)
{
if(bytes[cursor]==0x0d)
{
break;
}
else
{
cursor++;
}
}
char *pattern=(char *)malloc((cursor+1)*sizeof(char));
strncpy(pattern, bytes, cursor);
pattern[cursor]=0x00;
NSString *boundary=[[NSString alloc] initWithCString:pattern encoding:NSUTF8StringEncoding];
free(pattern);
return [self multipartDictionaryWithBoundary:boundary];
}
#end
For me, your code didn't work. Instead, I rewrote that code in pure objective-c:
Take care that (my) boundaries in this code always have additional -- in front of the next boundary and a final boundary - those are stripped.
An NSArray is returned with a NSDictionary for each part, containing the keys "headers" as NSDictionary and "body" as NSData
- (NSArray *)multipartArrayWithBoundary:(NSString *)boundary
{
NSString *data = [[[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding] autorelease];
NSArray *multiparts = [data componentsSeparatedByString:[#"--" stringByAppendingString:boundary]]; // remove boundaries
multiparts = [multiparts subarrayWithRange:NSMakeRange(1, [multiparts count]-2)]; // continued removing of boundaries
NSMutableArray *toReturn = [NSMutableArray arrayWithCapacity:2];
for(NSString *part in multiparts)
{
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *separated = [part componentsSeparatedByString:#"\n\n"];
NSMutableDictionary *headers = [NSMutableDictionary dictionaryWithCapacity:3];
for(NSString *headerLine in [[separated objectAtIndex:0] componentsSeparatedByString:#"\n"])
{
NSArray *keyVal = [headerLine componentsSeparatedByString:#":"];
[headers setObject:[[keyVal objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:[[keyVal objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
[toReturn addObject:[NSDictionary dictionaryWithObjectsAndKeys:[[separated objectAtIndex:1] dataUsingEncoding:NSUTF8StringEncoding], #"body", headers, #"headers", nil]];
}
return toReturn;
}