I am calling a web service which returns dictionary to render the graph. Dictionary structure is
{"1":0,"2":0,"8":0,"9":2,"10":3,"11":0,"12":0}
The problem is keys are dynamic values like 1,2,3 etc which indicates month. Is it possible to represent this in JsonModel?
See you cant create properties at run time as per response structure. But we can smartly use pre-defined things and achieve this. Do following steps:
Create one model class. So your MyCustomModel.h file will look like this
#import <Foundation/Foundation.h>
#interface MyCustomModel : NSObject
#property (nonatomic, retain) NSString * myCustomKey;
#property (nonatomic, retain) NSString * myCustomValue;
#end
This will be your MyCustomModel.m file
#import "MyCustomModel.h"
#implementation MyCustomModel
#synthesize myCustomKey, myCustomValue;
-(id)init {
self = [super init];
myCustomKey = #"";
myCustomValue = #"";
return self;
}
#end
Now lets suppose {"1":0,"2":0,"8":0,"9":2,"10":3,"11":0,"12":0} is NSDictionary and lets say its name is dictionaryResponse
Now do this stuffs:
NSArray *responseKeys = [[NSArray alloc]init];
responseKeys = [dictionaryResponse allKeys];
So your responseKeys will have all keys of response like ["1","2","8","9","10","11","12",]
Now you can iterate loop and create NSMutableArray of model objects as
NSMutableArray *arrayMonthList = [[NSMutableArray alloc]init];
for (int i = 0; i < responseKeys.count; i++) {
MyCustomModel *myModelObject = [[MyCustomModel alloc]init];
myModelObject.myCustomKey = [NSString stringWithFormat:#"%#",[responseKeys objectAtIndex:i]];
myModelObject.myCustomValue = [dictionaryResponse valueForKey:[NSString stringWithFormat:#"%#",[responseKeys objectAtIndex:i]]];
[arrayMonthList addObject:myModelObject];
}
Now arrayMonthList will consist of objects of type MyCustomModel
So you can use it and parse it. Even you can use it to show on UITableView. Following code is written to print values of model properties, you can customise at your expected level.
for (int i = 0; i < arrayMonthList.count; i++) {
MyCustomModel *myModelObject = [arrayMonthList objectAtIndex:i];
NSLog(#"Month is %# and its value is %#",myModelObject.myCustomKey,myModelObject.myCustomValue);
}
Related
I create the custom class name with FileModel.
FileModel.h
#import <Foundation/Foundation.h>
#interface FileModel : NSObject
#property (nonatomic, copy) NSString *fileName;
#property (nonatomic, copy) NSString *fileType;
#property (nonatomic, strong) NSDate *editDate;
#property (nonatomic, assign) NSInteger fileSize;
#end
I want to compare the particular string with the fileName.
I create the sample like below .m
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *fileSampleName = [[NSArray alloc] initWithObjects:#"apple.png",#"banana.png",#"cherry.png",#"durian.png",#"grape.png",#"avocado.png", nil];
NSMutableArray *fileData = [NSMutableArray new];
FileModel *fileModel = nil;
for( NSInteger i = 0 ; i < fileSampleName.count ; i++){
fileModel = [FileModel new];
fileModel.fileName = [fileSampleName objectAtIndex:i];
fileModel.fileType = #"photo";
fileModel.fileSize = 0;
fileModel.editDate = [NSDate new];
[fileData addObject:fileModel];
}
// fileData's fileName containsObject #"grape" or not?
}
NSArray has containsObject method.
But How can I check the #"grape" is containsObject using fileData at the custom class property filename?
I known using for loop compare one by one.
Did they have other method to check like containsObject?
--- edit---
I try to using indexOfObjectPassingTest method , But the result always is 1.
BOOL result = [fileData indexOfObjectPassingTest:^ BOOL (id tr,NSUInteger index, BOOL *te){
FileModel *fileModel = (FileModel*)tr;
if([#"orange" isEqualToString: fileModel.fileName]){
*te = YES;
return YES;
}else{
return NO;
}}];
NSLog(#"result:%#",#(result)); // it always return 1
Why? thank you very much.
Take a look that NSArray class reference in Xcode. One method you could use is indexOfObjectPassingTest. There are number of related methods depending on your needs. All take a block that's used to test objects to see if they meet whatever criteria you want. In your case you'd test the fileName string.
So you'd pass in a closure that compared the fileName property of each object to your desired filename.
I have copied some code that works fine for saving an api to one entity in core data over to save a similar api to another entity. Although everything is largely the same, I cannot get rid of exception error.
Here is the code that throws the exception:
- (NSMutableArray *) convertFeedtoObject:(NSMutableArray*)feed {
NSMutableArray * _newitems = [[NSMutableArray alloc] init];
for (int i = 0; i < feed.count; i++) {
NSDictionary *feedElement = feed[i];
ItemOnServer *newItem = [[ItemOnServer alloc] init];
newItem.itemtitle = feedElement[#"itemtitle"]; //throws exception
newItem.item = feedElement[#"item"];//also throws an exception if above commented out
newItem.descript = #"some item"; //if above lines commented out, littoral throws exception too.
//same goes for any other values I try to set. The first one throws exception.
Here is the error:
2015-11-20 05:26:03.281 [20610:60b] -[ItemOnServer setItem:]: unrecognized selector sent to instance 0x175721b0
No matter what values I try to set, I get a similar error even though I know the values are there.
One item of the feed looks like this:
{
lastviewed = "2015-11-17 15:21:45";
itemtitle = "New";
id = 944;
item = "cotton shirt";
}
)
Thanks for any suggestions.
Edit:
Code from ItemOnServer.h
//.m file is largely empty
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class ItemsVC;
#class Vendors;
#interface ItemOnServer : NSObject
#property (nonatomic, retain) NSString * item;
#property (nonatomic, retain) NSNumber * id;//this is permanent id shared with server
#property (nonatomic, retain) NSNumber * localid; //this is temp id if first created locally
#property (nonatomic, retain) NSString * itemtitle;
#property (nonatomic, retain) NSDate * lastviewed;
//this is relationship with vendors
#property (nonatomic, retain) Vendors *vendor;
#end
Instead of using an NSDictionary declare feedElement as an NSMutableArray, so something like:
- (NSMutableArray *) convertFeedtoObject:(NSMutableArray*)feed {
NSMutableArray * _newitems = [[NSMutableArray alloc] init];
NSMutableArray *feedElement = [[NSMutableArray alloc] init];
for (int i = 0; i < feed.count; i++) {
feedElement = feed[i];
ItemOnServer *newItem = [[ItemOnServer alloc] init];
newItem.itemtitle = feedElement[#"itemtitle"];
...
It looks like your class ItemOnServer doesn't have implementations for the methods setItem:, setItemtitle and so on. I don't know how you managed to do this, but you should look at the interface and implementation of ItemOnServer.
Look at what the error message says:
-[ItemOnServer setItem:]: unrecognized selector
That means a setItem: message is sent to an object, that object is an ItemOnServer object, and it doesn't implement setItem: The first two of these three points are exactly what you expect to happen when you write newItem.item = ...
Do you have another class named ItemOnServer in your application, maybe linked through some library? You can easily check by renaming ItemOnServer with ItemOnServer2 and checking what happens.
Using Objective-C, is it possible to go through an array by groups :
exemple :
NSArray *arr = 1, 2, 3, ....100;
Every 10 objects, do something and go on
so :
object 0 to 9 : you do something with each object and after the 10° object you do a last action
then object 10 to 19 : you do something with each object and after the 19° object you do a last action
and so on until the last object
thank you for your help
something like this:
for (int i = 0; i < arr.count; i++)
{
[self doSomethingWithArray];
if (i % 10 == 0)
[self doSomethingElse];
}
No it is not possible in Objective-C with in-built functions which matches your exact description. There are crude ways to do it by loops which matches your exact description.
But if you are aware before hand that you are going to make such type of operations, define your own data-structure. Create an NSObject sub-class, define your items (10 items which you were talking about) in it. Then in array, you can directly take out each instance of it comprising of your defined NSObject.
"enumerating by group"; If you want exactly as stated, you can subclass NSEnumerator.
For example:
In your Application code:
#import "NSArray+SubarrayEnumerator.h"
NSArray *arr = ...;
for(NSArray *grp in [arr subarrayEnumeratorEach:10]) {
// do what you want.
}
NSArray+SubarrayEnumerator.h
#import <Foundation/Foundation.h>
#interface NSArray (SubarrayEnumerator)
- (NSEnumerator *)subarrayEnumeratorEach:(NSUInteger)perPage;
#end
NSArray+SubarrayEnumerator.m
#import "NSArray+SubarrayEnumerator.h"
#interface _NSArraySubarrayEnumeratorEach : NSEnumerator
#property (assign, nonatomic) NSUInteger cursor;
#property (assign, nonatomic) NSUInteger perPage;
#property (strong, nonatomic) NSArray *src;
#end
#implementation NSArray (SubarrayEnumerator)
- (NSEnumerator *)subarrayEnumeratorEach:(NSUInteger)perPage {
_NSArraySubarrayEnumeratorEach *enumerator = [[_NSArraySubarrayEnumeratorEach alloc] init];
enumerator.perPage = perPage;
enumerator.src = self;
return enumerator;
}
#end
#implementation _NSArraySubarrayEnumeratorEach
- (id)nextObject {
NSUInteger start = _cursor;
if(start >= _src.count) {
return nil;
}
NSUInteger count = MIN(_perPage, _src.count - start);
_cursor += _perPage;
return [_src subarrayWithRange:NSMakeRange(start, count)];
}
#end
Hi I have an instance variable NSMutable Array.
I declare it as such
#property (nonatomic, assign) NSMutableArray *list;
In viewDidLoad I instantiate it.
self.list = [NSMutableArray array];
I then make a string consisting of the text of text fields and add it to the array.
NSString * lines = [NSString stringWithFormat:#"%#,%#,%#,%#,%#", [self.crabText text], [self.trawlText text], [self.trapText text], [self.vesselText text], [self.lengthText text]];
[self.list addObject:lines];
This is apart of a function which will keep on adding new values of the text fields into the array.
I display the contents of the array with
int i;
int count;
for (i = 0, count = [self.list count]; i < count; i = i + 1)
{
NSString *element = [self.list objectAtIndex:i];
NSLog(#"The element at index %d in the array is: %#", i, element); // just replace the %# by %d
}
However, the app crashes when I try to print the contents of the array and I get
EXC_BAD_ACCESS_CODE
Any ideas?
Thanks!
Replace your declaration like this :
#property (nonatomic, strong) NSMutableArray *list; // strong and not assign
Initialize your array in your viewDidLoad :
self.list = [NSMutableArray array];
and add one by one your string :
[self.list addObject:self.crabText.text];
[self.list addObject:self.trawlText.text];
....
Next, modify your for loop :
for (int i = 0, i < self.list.count, i++)
{
NSLog(#"The element at index %d in the array is: %#", i, [self.list objectAtIndex:i]);
}
Another way to do this would be to declare the array this way in your header file
#interface yourViewController : UIViewController
{
NSMutableArray* list;
}
#end
Then in the ViewDidLoad
list = [[NSMutableArray alloc] init];
Everything else can be done just as Jordan said. Though I'm not sure if there is a difference in performance between either implementation.
I have an NSMutableArray object (retained, synthesized as all) that is initiated just fine and I can easily add objects to it using the addObject: method. But if I want to replace an object at a certain index with a new one in that NSMutableArray, it doesn't work.
For example:
ClassA.h:
#interface ClassA : NSObject {
NSMutableArray *list;
}
#property (nonatomic, copy, readwrite) NSMutableArray *list;
#end
ClassA.m:
#import "ClassA.h"
#implementation ClassA
#synthesize list;
- (id)init
{
[super init];
NSMutableArray *localList = [[NSMutableArray alloc] init];
self.list = localList;
[localList release];
//Add initial data
[list addObject:#"Hello "];
[list addObject:#"World"];
}
// Custom set accessor to ensure the new list is mutable
- (void)setList:(NSMutableArray *)newList
{
if (list != newList)
{
[list release];
list = [newList mutableCopy];
}
}
-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex
{
int i = [theIndex intValue]-1;
[self.list replaceObjectAtIndex:i withObject:newTitle];
NSLog((NSString *)[self.list objectAtIndex:i]); // gives the correct output
}
However, the change remains true only inside the method. from any other method, the
NSLog((NSString *)[self.list objectAtIndex:i]);
gives the same old value.
How can I actually get the old object replaced with the new one at a specific index so that the change can be noticed from within any other method as well.
I even modified the method like this, but the result is the same:
-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex
{
int i = [theIndex intValue]-1;
NSMutableArray *localList = [[NSMutableArray alloc] init];
localList = [localList mutableCopy];
for(int j = 0; j < [list count]; j++)
{
if(j == i)
{
[localList addObject:newTitle];
NSLog(#"j == 1");
NSLog([NSString stringWithFormat:#"%d", j]);
}
else
{
[localList addObject:(NSString *)[self.list objectAtIndex:j]];
}
}
[self.list release];
//self.list = [localList mutableCopy];
[self setList:localList];
[localList release];
}
Please help out guys :)
This does the trick:
[myMutableArray replaceObjectAtIndex:index withObject:newObject];
OK, there are a few bits of confusion here.
You don't need to take a mutableCopy of a newly created NSMutableArray to make it mutable. It's already mutable -- the clue is in the name. You only need to do that in the setter if you want the property to have copy semantics (which you've set, and may have good reason for, of course). But you certainly wouldn't need to do it as shown in your updated updateTitle code, and doing so leaks localList.
Also, you're mixing together property access via self.list and direct use of list in the same method. This is not invalid, but it's bad practice, because it means whatever other stuff the accessor methods do is being randomly bypassed. It's common for properties like this to do everything through self except in the accessors themselves, or in dealloc, and possibly in init (opinions seem to differ on this), where you would access the ivar directly.
Also, never call [self.list release] -- the property accessor doesn't give its caller ownership. Doing this will end in tears, mark my words.
None of this answers the real question, which is why is your change disappearing. The original updateTitle code does not explain this as far as I can see -- it should work. So I suspect that somewhere else you are calling self.list = theOriginalList and hence undoing your change.
Update:
Just for the sake of argument, I'm going to post what I think the code you posted is probably meant to look like. I've preserved your use of a string to pass the index to updateTitle, but I'd like to point out that doing it this way is wrong. It's a number, you should pass it as such. Even if the number comes from a text field or something, that's the caller's concern; the class interface should specify a number. Similarly the apparent change from 1-based to 0-based indexing. Please do not do this sort of thing implicitly, it is a recipe for weeping and gnashing of teeth.
ClassA.h:
#import <Cocoa/Cocoa.h>
#interface ClassA : NSObject
{
NSMutableArray* list;
}
- (void) setList:(NSMutableArray*)newList;
- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex;
#property (nonatomic, copy, readwrite) NSMutableArray* list;
#end
ClassA.m:
#import "ClassA.h"
#implementation ClassA
#synthesize list;
- (id) init
{
if ( self = [super init] )
{
list = [[NSMutableArray alloc] init];
[list addObject:#"Hello "];
[list addObject:#"World"];
}
return self;
}
- (void) setList:(NSMutableArray*) newList
{
if ( list != newList )
{
[list release];
list = [newList mutableCopy];
}
}
- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex
{
int i = [theIndex intValue] - 1;
[self.list replaceObjectAtIndex:i withObject:newTitle];
}
- (void) dealloc
{
[list release];
[super dealloc];
}
#end
This cleans up various issues, but note that updateTitle is mostly the same. If you drop all this in and the change still doesn't survive, you are definitely resetting list somewhere.
A more straight answer would be:
self.list[i] = newTitle;
This just works like
[self.list replaceObjectAtIndex:i withObject:newTitle];
Look at this line:
#property (nonatomic, copy, readwrite) NSMutableArray *list;
The copy means that whenever you access self.list, you don't get the "_list" instance variable of your object, but a copy of that list. If you write [self.list replaceObjectAtIndex... ] you replace an object in that copy of your list; the original _list is unchanged. Just use
#property (nonatomic, strong, readwrite) NSMutableArray *list;
And to avoid confusion, remove the "list" instance variable and the #synthesize statement, then use _list to access the instance variable.
For Swift you could try:
//if you have indexPath
self.readArray.removeAtIndex((indexPath?.row)!)
self.readArray.insert(tempDict, atIndex: (indexPath?.row)!)
//tempDict is NSDictionary object.
Finally Got Some Perfect Code,
let DuplicateArray: NSArray = array
let DuplicateMutableArray: NSMutableArray = []
DuplicateMutableArray.addObjectsFromArray(DuplicateArray as [AnyObject])
var dic = (DuplicateMutableArray[0] as! [NSObject : AnyObject])
dic["is_married"] = "false"
DuplicateMutableArray[self.SelectedIndexPath] = dic
array = []
array = (DuplicateMutableArray.copy() as? NSArray)!
//Output Will Be Like
array = [
{
"name": "Kavin",
"Age": 25,
"is_married": "false"
},
{
"name": "Kumar",
"Age": 25,
"is_married": "false"
}
]