Loop in a model array - objective-c

I've this model:
#interface Data : NSObject
#property int Period;
#property (nonatomic, assign) NSDate *Start;
#property (nonatomic, assign) NSDate *End;
#end
#implementation Data
#synthesize Period, Start, End;
#end
I add data in mutable array.
#property (strong, nonatomic) NSMutableArray* myArray;
self.myArray = [NSMutableArray arrayWithCapacity:0];
Data *element1 =[ [Data alloc] init];
element1.Period = 1;
element1.Start = dateStart1;
element1.End = dateEnd1;
[self.myArray addObject:element1];
Data *element2 =[ [Data alloc] init];
element2.Period = 2;
element2.Start = dateStart2;
element2.End = dateEnd2;
[self.myArray addObject:element2];
Data *element3 =[ [Data alloc] init];
element3.Period = 3;
element3.Start = dateStart3;
element3.End = dateEnd3;
[self.myArray addObject:element3];
I can extract Start dates from array
Data * extractDateStart = [self.myArray valueForKey:#"Start"];
NSLog(#"All Start Dates: %#", extractDateStart);
I need to cycle for that array to search in which of the three period a specific date (inserted by user) is.
I know how to extract data from 'normal' array:
for(NSString * extractDate in self.myArray) {
NSLog(extractDate);
}
And know too how to compare one date with another:
switch ([dateInserted compare: date]) {
case NSOrderedAscending:
// dateInserted old than date
break;
case NSOrderedSame:
// dateInserted the same then date
break;
case NSOrderedDescending:
// dateInserted new then date
break;
default:
// generic error
break;
}
But how to move in this case ?

I might not understand your question, but it sounds like you:
Have a user provided NSDate
Want to find the Data object for which the NSDate falls between the Start and End dates
If that's the case, something like this should work:
NSDate *dateToFind = ...;
Data *foundData = nil; // We will put the correct Data object here if we find it
for (Data *data in self.myArray) {
// Test that dateToFind is between data.Start and data.End
if (([dateToFind compare:data.Start] != NSOrderedAscending)
&& ([dateToFind compare:data.End] != NSOrderedDescending)))
{
foundData = data; // dateToFind is in this Data's date range
}
}
// foundData is either nil or contains the Data you were looking for
For other good ways to test if a date falls between two other dates, see this question.

Related

Storing relational data in objects, overwrites values

I apologize for the lengthy question, ill try demonstrating the problem with examples.
I have three objects
Disease
Compound
Comdis
I am storing the list of Diseases and Compounds in respective classes.
The relations between Compounds and Diseases are to be stored in a list of objects called Comdis, Comdis stores pairs of (COMPOUND,DISEASE).
The example infromation that is to be stored in objects are.
DISEASES
index acronim fullname
1 AML, Acute Myelogenous Leukemia
2 PV, Polycytemia Vera
3 MF, Mielofibrosis
COMPOUNDS
index acronim fullname
1 LBH589, Panobinostat
2 INC424, Ruxolitinib
3 BKM120, Buparsinib
RELATIONS (COMDIS)
index disease compound
1 ( 0 , 1 )
2 ( 0 , 2 )
3 ( 0 , 3 )
4 ( 1 , 1 )
5 ( 1 , 2 )
6 ( 1 , 3 )
7 ( 2 , 1 )
8 ( 2 , 2 )
9 ( 2 , 3 )
My disease.h looks like this.
#interface disease: NSObject
{
NSString __strong *acronim;
NSString __strong *fullname;
int backcolor;
UIImage __strong *background;
}
#property (nonatomic) int backcolor;
#property (nonatomic, strong) UIImage *background;
#property (nonatomic, strong) NSString *acronim;
#property (nonatomic, strong) NSString *fullname;
#property NSMutableArray *list;
- (id)initWithDiseaseList;
- (int)getIndexByAcronim:(NSString *)acronim;
#end
disease.m has the following code
#import "disease.h"
#implementation disease
#synthesize acronim, fullname, backcolor, background;
-(id)initWithDiseaseList {
disease *aml = [[disease alloc] init];
[aml setAcronim:#"AML"];
[aml setFullname:#"Acute Myelogenous Leukemia"];
disease *pv = [[disease alloc] init];
[pv setAcronim:#"PV"];
[pv setFullname:#"Polycytemia Vera"];
disease *mf = [[disease alloc] init];
[mf setAcronim:#"MF"];
[mf setFullname:#"Mielofibrosis"];
NSMutableArray *array = [NSMutableArray array];
[array addObject:aml];
[array addObject:pv];
[array addObject:mf];
self.list = array;
return self;
}
- (int)getIndexByAcronim:(NSString *)accr {
NSArray *array = self.list;
for(int i = 0; i < [array count]; i++) {
disease *disease = [array objectAtIndex:i];
if(disease.acronim == accr) {
return i;
}
}
return -1;
}
#end
my compound.m is very similar to disease object.
now in comdis i want to store relations.
my comdis.h looks like this
#interface comdis: NSObject
{
int *icompound;
int *idisease;
}
#property (nonatomic,) int *icompound;
#property (nonatomic,) int *idisease;
#property NSMutableArray *list;
- (id)initWithComdisList;
#end
and this is my comdis.m
#import "comdis.h"
#import "compound.h"
#import "disease.h"
#implementation comdis
#synthesize idisease, icompound;
- (id)initWithComdisList {
compound *comp = [[compound alloc] initWithCompoundList];
disease *dis = [[disease alloc] initWithDiseaseList];
NSArray *compoundArray = comp.list;
NSArray *diseaseArray = dis.list;
NSMutableArray *array = [NSMutableArray array];
for(int i = 0; i < [diseaseArray count]; i++) {
for(int j = 0; j < [compoundArray count]; j++) {
int iCompoundIndex = [compoundArray indexOfObject:compoundArray[j]];
int iDiseaseIndex = [diseaseArray indexOfObject:diseaseArray[i]];
comdis *com = [[comdis alloc] init];
[com setIdisease:&iDiseaseIndex];
[com setIcompound:&iCompoundIndex];
[array addObject:com];
}
}
comdis *comdisObj = [self.list objectAtIndex:1];
int idis = *(comdisObj.idisease);
int icom = *(comdisObj.icompound);
NSLog(#"%d", idis);
NSLog(#"%d", icom);
return self;
}
#end
The problem is if i try printing the value of idis or icom it always prints 2 regardless of objectAtIndex value i give. it seems the value in loop is being overwritten and it always takes the last value of loop, i am a beginner to objective-c and will appreciate if someone could put some light on what is wrong with my code.
Sorry again for lengthy explanation and code.
[com setIdisease:&iDiseaseIndex];Because all comdis object's property disease and compound refer to the same address, they all equal to the value of last added object. To overcome this problem, you may use int property instead of *int in comdis.

Extracting data from array only last shown

I've this model:
#interface Data : NSObject
#property (nonatomic, assign) int Period;
#property (nonatomic, assign) NSDate *Start;
#property (nonatomic, assign) NSDate *End;
#end
#implementation Data
#synthesize Period, Start, End;
#end
I add data in mutable array.
#property (strong, nonatomic) NSMutableArray* myArray;
self.myArray = [NSMutableArray arrayWithCapacity:0];
Data *element =[ [Data alloc] init];
element.Period = 1;
element.Start = dateStart1;
element.End = dateEnd1;
[self.myArray addObject:element];
element.Period = 2;
element.Start = dateStart2;
element.End = dateEnd2;
[self.myArray addObject:element];
element.Period = 3;
element.Start = dateStart3;
element.End = dateEnd3;
[self.myArray addObject:element];
Why when extract Period from array i receive only the last element x 3 ???
Data * NumElement = [self.myArray valueForKey:#"Period"];
NSLog(#"All period: %#", NumElement);
and i receive 3 3 3 instead of 1 2 3 ?
You instantiate a single object, add it to the array, then change that same object and add it again to the array, etc. The array ends up holding 3 references to the same object, with the values last assigned to it.
Try this:
Data *element1 =[ [Data alloc] init];
element1.Period = 1;
element1.Start = dateStart1;
element1.End = dateEnd1;
[self.myArray addObject:element1];
Data *element2 =[ [Data alloc] init];
element2.Period = 2;
element2.Start = dateStart2;
element2.End = dateEnd2;
[self.myArray addObject:element2];
Data *element3 =[ [Data alloc] init];
element3.Period = 3;
element3.Start = dateStart3;
element3.End = dateEnd3;
[self.myArray addObject:element3];
That's because you're putting the same object into your array over and over again. No matter how many times you add it, no matter which of its properties you change, it's the same object.
You need to instantiate an object for each set of data.

incompatible pointer type?

I am a newbie in programming, currently across some difficulties in my first school work. Can anyone tell me am I doing on the right track? The aim of this code is to do add two numbers around 70 digits which cannot be done using the int or long int type in Objective-C. The following code keeps getting warning: incompatible pointer types returning 'NSString *__strong' from a result type 'MPInteger *' Help please, I have already been figuring out for ages and got nothing.
MPInteger.h
#import <Foundation/Foundation.h>
#interface MPInteger : NSObject
#property (copy, nonatomic) NSString * description;
-(id) initWithString: (NSString *) x;
-(NSString *) description;
-(MPInteger *) add: (MPInteger *) x;
MPInteger.m
#import "MPInteger.h"
#implementation MPInteger
#synthesize description;
-(id) initWithString: (NSString *) x {
self = [super init];
if (self) {
description = [NSString stringWithString: x];
}
return self;
}
-(NSString *) description {
return description;
}
-(MPInteger *) add: (MPInteger *) x
{
int carry = 0;
int index = 0;
int index2 = 0;
int i;
int num1;
int num2;
int result;
index = [description length];
index2 = [x.description length];
while (index2 < index) {
x.description = [x.description stringByPaddingToLength:index withString:#"0" startingAtIndex:0];
}
for (i = index; i <= index || carry != 0; i--) {
num1 = [description characterAtIndex:index];
num2 = [x.description characterAtIndex:index];
result = num1 + num2 + carry;
// if the sum is less than 10
if (result < 10) {
NSString *intString = [NSString stringWithFormat:#"%i", result];
[description replaceValueAtIndex:index inPropertyWithKey:intString withValue:#"%#"];
// replace the description index value with the sum
} else { //otherwise
NSString *intString = [NSString stringWithFormat:#"%i", result];
//getting the index'1' is the value replace the description index value
[description replaceValueAtIndex:index inPropertyWithKey:[intString substringFromIndex:1] withValue:#"%#"];
carry = 1;
}
index--; // decrement index
}
return description;
}
You declare your method to return an MPInteger:
- (MPInteger *)add:(MPInteger *)other;
but you finally return description, which is an NSString instance.
You perhaps meant to make an MPInteger instance out of the string before returning:
return [[MPInteger alloc] initWithString:description];
(add autorelease if you don't use ARC).
It's pretty much exactly what the error says:
#property (copy, nonatomic) NSString * description;
[...]
-(MPInteger *) add: (MPInteger *) x
{
[...]
return description;
}
You say that your add method will return a reference to a MPInteger object but your code returns a reference to a NSString instead. You need to make those match, either by declaring a string type of return value for the method or by returning an instance of MPInteger.
The warning is beacuse you're returning description from your add: method but description is an NSString. You need description to be an MPInteger.
Unfortunately, NSObject already has a method calleddescriptionwhich returns anNSString. It's this method that's called each time you use%#` in a format string i.e.
NSLog(#"I am %#", self);
will actually call description on self and put it into the string in place of the %#.
At the end of your method, you need to return an MPInteger instead of description. Try replacing
return description;
with
MPInteger newInteger = [MPInteger new];
newInteger.description = description;
return newInteger;
to return a new integer.

how to get different array on different index of single array

i have one array named invoiceInfo1 & i pass it to another array named allInfo.
But I want for different index of invoiceInfo ,the different array is created & pass it to allInfo.
Mycode is as follow:
for (int i=0; i<[userdata count]; i++) {
NSLog(#" userdata count :%d",[userdata count]);
invoiceInfo1 = [NSMutableArray arrayWithObjects:[[userdata objectAtIndex:i]valueForKey:#"fname"], [[userdata
objectAtIndex:i]valueForKey:#"name"],
[[userdata objectAtIndex:i]valueForKey:#"address"],
[[userdata objectAtIndex:i]valueForKey:#"city"], nil];
NSLog(#" info1 is:%#",invoiceInfo1); // invoiceInfo get overwrite when loop execute
NSMutableArray* allInfo = [NSMutableArray arrayWithObjects:headers,invoiceInfo1 , nil];
// HERE I Want Generate New Array of different index of invoiceInfo1 & pass it to allInfo
}
Create a NSObject class with header and info array:
#interface AllInfo: NSObject
{
NSMutableArray *header;
NSMutableArray *info;
}
#property (nonatomic, retain) NSMutableArray *header;
#property (nonatomic, retain) NSMutableArray *info;
#end
#implementation AllInfo
#synthesize header;
#synthesize info;
#end
Then implement this code:
allInfo = [[NSMutableArray alloc] init];
for (int i=0; i<[userdata count]; i++) {
NSLog(#" userdata count :%d",[userdata count]);
NSMutableArray *invoiceInfo1 = [[NSMutableArray alloc] init];
[invoiceInfo1 addObject:[userdata objectAtIndex:i]valueForKey:#"fname"]];
[invoiceInfo1 addObject:[userdata objectAtIndex:i]valueForKey:#"name"]];
[invoiceInfo1 addObject:[userdata objectAtIndex:i]valueForKey:#"address"]];
[invoiceInfo1 addObject:[userdata objectAtIndex:i]valueForKey:#"city"]];
NSLog(#" info1 is:%#",invoiceInfo1); // invoiceInfo get overwrite when loop execute
AllInfo *newInfo = [[AllInfo alloc] init];
newInfo.header = headers;
newInfo.info = invoiceInfo1;
[allInfo addObject:newInfo];
// HERE I Want Generate New Array of different index of invoiceInfo1 & pass it to allInfo
}
Hope this will help.

Is there a way to specify a specific object index in a valueForKeyPath statement?

In calling NSDictionary valueForKeyPath if one level of the path is an array can you specify a specific element in the array?
For example:
[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers[4].countryCode];
where .phoneNumbers is an NSArray. Or do I have to:
NSArray *numbers=[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers];
NSString *countryCode=[[numbers objectAtIndex:4] objectForKey:#"countryCode"];
It would be really nice and much cleaner if this could be done in one statement.
You could do this:
NSString *myString = [[[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers"] objectAtIndex:4] objectForKey:#"countryCode"];
Here's a category I wrote for NSObject that can handle array indexes so you can access your nested object like this: "customer.contactInfo.phoneNumbers[4].countryCode"
#interface NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath;
#end
#import "NSObject+ValueForKeyPathWithIndexes.h"
#implementation NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath
{
//quickly use standard valueForKeyPath if no arrays are found
if ([fullPath rangeOfString:#"["].location == NSNotFound)
return [self valueForKeyPath:fullPath];
NSArray* parts = [fullPath componentsSeparatedByString:#"."];
id currentObj = self;
for (NSString* part in parts)
{
NSRange range = [part rangeOfString:#"["];
if (range.location == NSNotFound)
{
currentObj = [currentObj valueForKey:part];
}
else
{
NSString* arrayKey = [part substringToIndex:range.location];
int index = [[[part substringToIndex:part.length-1] substringFromIndex:range1.location+1] intValue];
currentObj = [[currentObj valueForKey:arrayKey] objectAtIndex:index];
}
}
return currentObj;
}
#end
Use it like so
NSString* countryCode = [myDict valueForKeyPathWithIndexes:#"customer.contactInfo.phoneNumbers[4].countryCode"];
There's no error checking, so it's prone to breaking but you get the idea. I cross posted this answer to a similar (linked) question.