NSDictionary: Comparison after MutableCopy - objective-c

I have the following properties:
#property (retain, nonatomic) NSMutableDictionary * firstStartTimeObject;
#property (retain, nonatomic) NSMutableDictionary * firstLocationNameObject;
#property (retain, nonatomic) NSMutableDictionary * firstLocationAddressObject;
#property (retain, nonatomic) NSMutableDictionary * secondStartTimeObject;
#property (retain, nonatomic) NSMutableDictionary * secondLocationNameObject;
#property (retain, nonatomic) NSMutableDictionary * secondLocationAddressObject;
//This is how I make copies of the Dictionaries:
-(DataClass *)copyObjects
{
DataClass *newClass = [[DataClass alloc]init];
newClass.firstStartTimeObject = [firstStartTimeObject mutableCopy];
newClass.firstLocationAddressObject = [firstLocationAddressObject mutableCopy];
newClass.firstLocationNameObject = [firstLocationNameObject mutableCopy];
newClass.secondStartTimeObject = [secondStartTimeObject mutableCopy];
newClass.secondLocationNameObject = [secondLocationNameObject mutableCopy];
newClass.secondLocationAddressObject = [secondLocationAddressObject mutableCopy];
return newClass;
}
//In another Class I compare them
if([myClass.firstStartTimeObject isEqualToDictionary:dataClass.firstStartTimeObject])
{
[dataClass.firstStartTimeObject setValue:kCellBackGroundColor forKey:kBackGround];
}
if([myClass.firstLocationNameObject isEqualToDictionary:dataClass.firstLocationNameObject])
{
[dataClass.firstLocationNameObject setValue:kCellBackGroundColor forKey:kBackGround];
}
if([dataClass.firstLocationAddressObject isEqualToDictionary:dataClass.firstLocationAddressObject])
{
[dataClass.firstLocationAddressObject setValue:kCellBackGroundColor forKey:kBackGround];
}
if([myClass.secondStartTimeObject isEqualToDictionary:dataClass.secondStartTimeObject])
{
[dataClass.secondStartTimeObject setValue:kCellBackGroundColor forKey:kBackGround];
}
if([myClass.secondLocationNameObject isEqualToDictionary:dataClass.secondLocationNameObject])
{
[dataClass.secondLocationNameObject setValue:kCellBackGroundColor forKey:kBackGround];
}
if([myClass.secondLocationAddressObject isEqualToDictionary:dataClass.secondLocationAddressObject])
{
[dataClass.secondLocationAddressObject setValue:kCellBackGroundColor forKey:kBackGround];
}
I have Break points setup. Keys/Values in comparing dictionaries is identical, but it seems like the compiler looks at them differently as the condition is never true for it to make it inside the braces and hit the breakpoint.
I verified the keys/values via NSLog and they are identical. I even tried protocol with - (id)mutableCopyWithZone:(NSZone *)zone and got the same behavior.
Does mutableCopy of an NSMutableDicitonary change its copy to where without changing any of its contents, you compare it to the source and it's not the same? I can't figure out what I'm doing wrong!

Two dictionaries have equal contents if they each hold the same number of entries and, for a given key, the corresponding value objects in each dictionary satisfy the isEqual: test. This is how equaltodictionary work .so the issue looks like your contents is not holding the same number of entries. Please recheck your mutabledictinary object. And one more thing i have noticed is that your one if condition where you are comparing same dataclass in-spite of having one myclass.

Related

Searching and Modifying NSMutableArray object with updated values

I have constructed my model object with following.
#property (strong, nonatomic) NSString *id;
#property (strong, nonatomic) NSString *somevalue;
#property (strong, nonatomic) NSString *another value;
#property (strong, nonatomic) NSString *xtz;
#property (strong, nonatomic) NSString *st;
#property (strong, nonatomic) NSMutableArray *sc;
Now my mutable array is filled with following sample objects,
{a = 1;b = 6;c = 0;},{a = 2;b = 7;c = 0;},{a = 2;b = 8;c = 0;},{a = 3;b=9;c = 0;}
There are roughly 200 of such objects in my array. Now I cannot figure out a decent way of looping through the array updating the value of for example 'c' to '1' where 'a' ==1.
I could use a for loop like that:
for(int i = 0 ; i <myobject.sc.count; i++) {
NSLog(#"%#",[[myobject sc]objectAtIndex:i]);
}
It would allow me to iterate through the array. But still face the problem of looping through values contains within each object. Maybe a nested loop?
All you need is a simple loop:
for (WhateverDataType *data in myobject.sc) {
if (data.a == 1) {
data.c = 1
// break // uncomment if you only want to update the first match
}
}
This gives you a general idea for the solution. The specific syntax depends on what type of objects are actually in the mutable array.

How to do deep copying Objective-C

There is a class Patient with properties:
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) Symptoms *symptoms;
#property (assign, nonatomic) Status status;
#property (weak, nonatomic) id <PatientDelegate> delegate;
There is a class Symptoms with properties:
#property (assign, nonatomic) CGFloat temperature;
#property (assign, nonatomic) BOOL headache;
#property (assign, nonatomic) BOOL stomach_ache;
Both classes implement protocol NSCopying:
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
Patient *newPatient = [[[self class] allocWithZone:zone] init];
[newPatient setName:self.name];
[newPatient setSymptoms:self.symptoms];
[newPatient setStatus:self.status];
[newPatient setDelegate:self.delegate];
return newPatient;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
Symptoms *newSymptoms = [[[self class] allocWithZone:zone] init];
[newSymptoms setTemperature:self.temperature];
[newSymptoms setHeadache:self.headache];
[newSymptoms setStomach_ache:self.stomach_ache];
return newSymptoms;
}
Also there is a class Doctor:
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSMutableArray *history;
- (void)makeNoteIn:(Patient *)patient card:(NSMutableArray *)history;
- (void)report;
When patient gets well, doctor calls method makeNoteIn:
- (void)makeNoteIn:(Patient *)patient card:(NSMutableArray *)history {
Patient *newRecord = [patient copy];
[history addObject:newRecord];
}
After the record is made, all property of the patient return to the original values. While we are in the method makeNoteIn and the current patient is proceeded, in history there is link to this object which has correct property values. As soon as we exit the method or start to proceed another patient, all the property values reset to the initial value.
I tried to realise copying, but something still wrong.
When you want to deep-copy an object, you have to implement copy on all the substructures:
[newPatient setName:[self.name copy]];
[newPatient setSymptoms:[self.symptoms copy]];
Otherwise they will still reference the same object and changing one will affect all.
Note that you can do that automatically by declaring the properties as copy:
#property (copy, nonatomic) NSString *name;
#property (copy, nonatomic) Symptoms *symptoms;
It's common to use copy with NSString and NSArray to prevent assigning NSMutableString and NSMutableArray which could be changed externally by mistake. Make sure you implement NSCopying on Symptoms.

Using MagicalRecord, how do I get data out of NSArray and into a NSManagedObject?

I am using MagicalRecord to work with Core Data objects. I am having problems with retrieving Core Data objects using the NSArray that MR puts them into... I can't seem to get the data out of the array and into a NSManagedObject so I can work with it. Here is my code:
// create the predicate
NSArray *apptDataArray = [NSMutableArray new];
NSPredicate *predicate = ([NSPredicate predicateWithFormat:#"((aStartTime > %#) AND (aStartTime <= %#))", startDate, endDate]);
// find all appointments with that selected date
apptDataArray = [AppointmentInfo MR_findAllWithPredicate:predicate];
// now find the appointments for the selected date and put them in the schedule
if(apptDataArray.count > 0) {
for (NSManagedObject *AppointmentInfo in apptDataArray) {
NSLog(#"\n\n-->apptDataArray: %#", apptDataArray);
}
}
This is the definition for AppointmentInfo which is in a different class:
#interface AppointmentInfo : NSManagedObject
#property (nonatomic, retain) NSDate * aStartTime;
#property (nonatomic, retain) NSDate * aEndTime;
#property (nonatomic, retain) NSString * aServiceTech;
#property (nonatomic, retain) NSString * aApptKey;
#property (nonatomic, retain) NSDate *aShortDate;
Somehow, I need to get to the data which is in the returned array and place it in AppointmentInfo. I have tried all kinds of permutations, looked in Google and SO, but I couldn't find anything. I'm stumped! How do I do it?
I am not sure if I understand your problem correctly, but
the result apptDataArray of the fetch request is just an array of AppointmentInfo objects, so you can access individual objects with
AppointmentInfo *appt = [apptDataArray objectAtIndex:i]; // 0 <= i < apptDataArray.count
or enumerate all objects of the result array with
for (AppointmentInfo *appt in apptDataArray) {
NSLog(#"startTime=%#, endTime=%#", appt.aStartTime, appt.aEndTime);
}

How to avoid temp objects when returning NSString under ARC

I've got a class with two properties:
#interface Contact : NSObject {
NSString *lastname;
NSString *lastNameUpper;
}
I've declared lastname as a property (and synthesize it in the .m-file):
#property (nonatomic, retain) NSString *lastname;
However, I want to write my own method to access the lastNameUpper, so I declared a method:
- (NSString *) lastNameUpper;
and implemented it like this:
- (NSString *) lastNameUpper {
if (!lastNameUpper) {
lastNameUpper = [lastname uppercaseString];
}
return lastNameUpper;
}
This works all right, but as this is called quite often, a lot of temporary objects are called. Interestingly, the Instruments show a lot of "Malloc (4k)", and the number increase each time lastNameUpper is accessed. I can also see that the memory is allocated in objc_retailAutoreleaseReturnValue.
As this was working fine before I converted my project to ARC, I'm assuming that I have to make some ARC specific additions to the method signature, but I can't seem to be able to make it work.
Any suggestions?
0: you should copy your NSString properties:
#property (nonatomic, copy) NSString * lastname;
I'm guessing that returning the string is implemented by copying it.
nope. copy of an immutable string is a retain operation. just run it in the profiler to see how much this costs in time and memory. also, there's no implicit copy in this case.
Update
I tested this on Lion-64. uppercaseString may return a mutable string.
To be safe, you may consider assigning a copy of the result of uppercaseString: lastNameUpper = [[lastname uppercaseString] copy];. that may result in more or less allocations, depending on how you used the string in your implementation. if your properties copy, then a copy will be made each time you assign it. the easy generalization is to assign a copy, and the rest usually takes care of itself.
Test Program
// ARC enabled
#import <Foundation/Foundation.h>
#interface Contact : NSObject
{
NSString * lastname;
NSString * lastNameUpper;
}
#property (nonatomic, copy) NSString *lastname;
#end
#implementation Contact
#synthesize lastname;
- (NSString *) lastNameUpper {
if (!lastNameUpper) {
lastNameUpper = [lastname uppercaseString];
}
return lastNameUpper;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
int n = 0;
while (n++ < 100000) {
Contact * c = [Contact new];
c.lastname = #"skjdhskjdhaksjhadi";
NSString * lastNameUpper = c.lastNameUpper;
}
}
return 0;
}
Override the - (void)setLastname:(NSString*)aLastname method (created automatically by #synthesize lastname, and set lastNameUpper as in the existing method.
Now create a lastNameUpper property (and synthesize it):
#property (nonatomic, readonly) NSString *lastNameUpper;
Since this will return the pointer of the lastNameUpper instance variable, no copies should be made whenever this is accessed.

Macro for defining kvc assessors in objective-c

Is there any macro to help simplify the creation of KVC macros in Objective C? As it stands in order to create a to-many mutable KVC compliant property is extremely tedious, to define a single property it takes the following
//Code.h
#property (strong, nonatomic, readonly) NSArray *prevSearches;
//Code.m
#property (strong, nonatomic, readwrite) NSArray *prevSearches;
...
#synthesize prevSearches = _prevSearches;
- (void)prevSearches {
return [_prevSearches copy];
}
- (void)setPrevSearches:(NSArray *)prevSearches {
_prevSearches = [NSMutableArray arrayWithArray:prevSearches];
}
- (void)insertObject:(SavedSearch *)object inPrevSearchesAtIndex:(NSUInteger)index {
[_prevSearches insertObject:object atIndex:index];
}
- (void)removeObjectFromPrevSearchesAtIndex:(NSUInteger)index {
[_prevSearches removeObjectAtIndex:index];
}
That's over 20 lines to define a single property, I often have several in a particular class... Surely there's an easier way?
have you tried a sofware like accessorizer?
http://itunes.apple.com/it/app/accessorizer/id402866670?mt=12
otherwise i think that a simple bash script can save your time ;)