substitute to switch statement in objective c - ios4

I am loading a tableview with the contents from web service using json frameworks in asynchronous connection. The data is in the json object form
{"id":1,"firstName":"A","lastName":"B","email":"abc#yahoo.com","salary": {"monthly":$5000,"annual":$60000}}
I am loading tableview using switch statement in cellForRowAtIndexPath:
dictionaryData = [responseString JSONValue];
switch (indexPath.row)
{
case 0:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %# %#",#"Name",[dictionaryData valueForKey:#"firstName"],[dictionaryData valueForKey:#"lastName"]];
break;
case 1:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Email",[dictionaryData valueForKey:#"email"]];
break;
case 2:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Monthly Salary",[[dictionaryData valueForKey:#"salary"]valueForKey:#"monthly"]];;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case 3:
cell.textLabel.text = [NSString stringWithFormat:#"%# : %#",#"Annual Salary",[[dictionaryData valueForKey:#"salary"]valueForKey:#"annual"]];
break;
default:
break;
}
This is for normal data, but when i have more fields like phone number, address, department number, etc , then writing too many cases will make the method very large.Can someone help me how i can do this without switch.

You are going about this the wrong way. You want to create arrays and index them using indexpath.row. So you ll have only one line of assigning cell.textLabel.text. One solution is:
Create an NSArray of objects beforehand containing your #"Name",#"E-Mail" etc. like:
NSArray *arr1=[NSArray arrayWithObjects:#"Name",#"Email",....,nil];
Then when you get the NSDictionary,store it in an array and enumerate through it like
NSMutableArray *arr2=[dictionaryData allValues];
for(id obj in arr2)
{
if([obj isKindOfClass:[NSString class]])
[arr2 addObject:obj];
else if([obj isKindOfClass:[NSDictionary class]])
{
[arr2 addObject:[obj valueForKey:#"Monthly"]];
[arr2 addObject:[obj valueForKey:#"Annual"]];
}
}
Then just use indexpath.row in cell.textLabel.text
cell.textLabel.text=[NSString stringWithFormat:#"%# : %#",[arr1 objectAtIndex:indexPath.row],[arr2 objectAtIndex:indexPath.row]];
Of course there might be a better way specific to your case, but this should help you build that.

Related

Core Data Problems with saving changes in NSManagedObjectContext

I am experiencing problems with how I handle my Core Data NSManagedObjectContext.
I can create NSManagedObject in my NSManagedObjectContext, but I failed to save the value.
Here's what I got:
_lesson.title = _titleField.text;
int priority = [_priorityField.text intValue];
int difficulty = [_difficultyField.text intValue];
int time = [_timeField.text intValue];
int sortIndex = 0;
if ( time == 0 )
{
sortIndex = 101;
}
else
{
sortIndex = priority * ( difficulty / time );
}
_lesson.priority = [NSNumber numberWithInt:priority];
_lesson.difficulty = [NSNumber numberWithInt:difficulty];
_lesson.time = [NSNumber numberWithInt:time];
_lesson.sortIndex = [NSNumber numberWithInt:sortIndex];
NSError* error = nil;
[[(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext] save:&error];
Everything before the saving is working perfectly, I used NSLog to verify if each value is really saved in _lesson.
And _lesson is sent from here:
if ( [[segue identifier] isEqualToString:#"addLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
Lesson* lesson = (Lesson*)[NSEntityDescription insertNewObjectForEntityForName:#"Lesson" inManagedObjectContext:_managedObjectContext];
destination.lesson = lesson;
}
else if ( [[segue identifier] isEqualToString:#"editLesson"] )
{
LessonViewController* destination = [[LessonViewController alloc]init];
NSIndexPath* index = [_tableView indexPathForCell:(UITableViewCell*)sender];
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
Lesson* lesson = (Lesson*)[_lessonArray objectAtIndex:index.row];
destination.lesson = lesson;
}
After debugging for two hours, I cannot find my error. Please help!
I will include my full code below:
https://www.dropbox.com/sh/eu62ie9svbbqdmm/u1hYUICfjy
That is my full source code. (I copied and pasted and created a mess. So, Dropbox!)
Thanks in advance.
This line looks suspicious:
[_managedObjectContext deleteObject:[_lessonArray objectAtIndex:index.row]];
You delete the Lesson object before passing it to the LessonViewController, so that saving the context will delete that object from the store, and not save a (modified) object, as you probably intended.
It seems to me that you should just delete that line in your code.
ADDED: There is an error in your prepareForSegue method: You create a new view controller with
LessonViewController* destination = [[LessonViewController alloc]init];
Instead, you must use the destination view controller of the seque:
LessonViewController *destination = [segue destinationViewController];

NSComparisonPredicate to find empty strings

I need to check if a string in my array is empty using the NSComparisonPredicate. The predicate that is being executed is: string MATCHES[c] ""
But nothing shows up in the results, it does not list my empty strings.
Is my predicate wrong or there is just another way of dealing with empty strings with NSPredicate?
I'm not sure why you're using NSComparisonPredicate ,I've never used that one, so I'm not familiar with it. Have you tried predicateWithFormat?
NSPredicate *pred = [NSPredicate predicateWithFormat:#"self.length == 0"];
It's not clear how you want to use the predicate, but this should work if you're using it to filter an array.
If you want to know the indexes of strings in your array that are empty, then you could use indexesOfObjectsPassingTest: like so:
NSIndexSet *indxs = [array indexesOfObjectsPassingTest:^BOOL(NSString *aString, NSUInteger idx, BOOL *stop) {
return aString.length == 0;
}];
NSLog(#"%#",indxs);
As rdelmar mentions above, for such a task you should just check the length of the string by string.length==0
You can filter your array using blocks. I would recommend that approach against using NSPredicate. Here is some sample code:
//creating array
NSArray *myArray = [NSArray arrayWithObjects:#"a", #"b", #"", #"c", nil];
//filtering
NSIndexSet *iset = [myArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSString *str = obj;
return !str.length;
}
];
//creating my result array with empty strings
NSArray *emptyStrings = [myArray objectsAtIndexes:iset];
//logging all strings
for (NSString *str in myArray) {
NSLog(#"string: %#", str);
}
//logging empty strings
for (NSString *str in emptyStrings) {
NSLog(#"empty string: %#", str);
}
EDIT:
If you really need to use NSComparisonPredicate, here it is:
NSExpression *left = [NSExpression expressionForKeyPath:#"length"];
NSExpression *right = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:0]];
NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
NSPredicateOperatorType operator = NSEqualToPredicateOperatorType;
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:modifier type:operator options:0];
NSArray *filtered = [myArray filteredArrayUsingPredicate:predicate];

UISwitch core data

UITextField *textField;
UISwitch *someSwitch;
NSManagedObject *editedObject;
NSString *editedFieldKey;
NSString *editedFieldName;
NSString *z=[NSString stringWithFormat:#"%#",[editedObject valueForKey:editedFieldKey]];
NSString *y=[NSString stringWithFormat:#"b"];
if(z==y){
[someSwitch setOn:YES animated:YES];
}
else{[someSwitch setOn:NO animated:YES];}
-(IBAction) toggleButtonPressed{
NSString *a=[NSString stringWithFormat:#"a"];
NSString *b=[NSString stringWithFormat:#"b"];
if(someSwitch.on){
[editedObject setValue:b forKey:editedFieldKey];
}
else{
[editedObject setValue:a forKey:editedFieldKey];
}
}
-(IBAction)save {
NSUndoManager * undoManager = [[editedObject managedObjectContext] undoManager];
[undoManager setActionName:[NSString stringWithFormat:#"%#", editedFieldName]];
if (editingName){
[editedObject setValue:textField.text forKey:editedFieldKey];
}else{
[self toggleButtonPressed];
}
[self.navigationController popViewControllerAnimated:YES];
}
I can't get a UISwitch to work in the context of Core Data and detail view controllers. When you create a BOOL in core data, then have the corresponding class made in xcode, it makes an NSNumber. This is fine but instead of making "0" and "1"'s when data is saved and recalled, it comes up with very large integers (7-8 digits). What I did above was to store the information as a binary string, using "a" or "b" for the string for storage. This hasn't worked well, mostly because I can't get the UISwitch to load with the previously stored value (on or off). I am sure this has been dealt with before, but I can't find much documentation online. If there are any ideas or suggestions, relative to the above code, let me know. Thanks.
2011-12-06 15:49:41.042 sampNav[820:207] 101783056
2011-12-06 15:49:41.043 sampNav[820:207] 80887600
- (IBAction)save {
NSUndoManager * undoManager = [[editedObject managedObjectContext] undoManager];
[undoManager setActionName:[NSString stringWithFormat:#"%#", editedFieldName]];
if (editingName){
[editedObject setValue:textField.text forKey:editedFieldKey];
}else{
[self toggleButtonPressed];
}
[self.navigationController popViewControllerAnimated:YES];
}
-(IBAction) toggleButtonPressed{
if (someSwitch.on==YES)
{
[editedObject setValue:[NSNumber numberWithInt:1] forKey:editedFieldKey];
NSLog(#"%d",[editedObject valueForKey:editedFieldKey]);
}
else [editedObject setValue:[NSNumber numberWithInt:0] forKey:editedFieldKey];
NSLog(#"%d",[editedObject valueForKey:editedFieldKey]);
}
The problem is when these values are stored as NSNumber objects the values are large integers. The NSLog is given at the very top. Can anyone explain this?
your code as it stands:
if(z==y){
Is comparing pointers not the strings, you need:
if([z isEqualToString:y]){
To get the string comparison to work so that the switch has the correct initial state...
But you really want to use the core data BOOL version and get the value of the NSNumber that is stored in the NSManagedObject. I suspect you are not converting the NSNumber pointer to object into a boolValue.
if([[editedObject valueForKey:editedFieldKey] boolValue]) {

Store array of ABRecordRef

How can we store and access a list of ABRecordRef so that we can use this in another class and later on?
You can get recordId from the record of type ABRecordRef from
addressBook Then convert it into NSString. Store it in NSUserDefaults
When you want to fetch the record...
fetch that recordId from NSUserDefaults,Convert it in integer
then use
ABRecordRef myRecord =
ABAddressBookGetPersonWithRecordID(addressBook, recordId);
So you will get the record which you saved earlier.
Try This:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef person = ABRecordGetRecordID(1); // Or whatever you're using to get the record.
// do this for each piece of information you need:
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
// Get your receiving dict ready:
NSMutableDictionary *personDict = [NSMutableDictionary dictionary];
// then test them for a value (don't want nil values in the dictionary)
// Add each value as you test it.
if (firstName) {
[personDict setObject:firstName forKey:#"FistName"];
}
if (lastName) {
[personDict setObject:lastName forKey:#"LastName"];
}
// Add the personDict to NSUserDefaults:
[[NSUserDefaults standardDefaults] setObject:personDict forKey:#"MyPersonsDictionary"];
// Clean up after yourself:
[firstName release];
[lastNmae release];
That should be it.

Core Data Transient Calculated Attributes

I have an entity that contains lastName and firstName attributes. For reasons beyond the scope of this question, I want a fullName attribute that gets calculated as a concatenation of firstName + space + lastName.
Because this is purely a calculated value, with no need for redo/undo or any other of the more sophisticated aspects of transient attributes (merging, etc.), my gut tells me to just override the getter method to return said calculated value. Reading suggests that, if I do this, my only concern would be whether it's KVO compliant, which I can address by using keyPathsForValuesAffectingVolume to ensure changes to firstName or lastName trigger notifications for anyone observing on fullName.
Am I missing anything? I'm checking because I'm a beginner to this environment.
I'm also new to this, so I'm not completely sure about my answer, but as I understand it you are correct.
- (NSString *)fullName
{
[self willAccessValueForKey:#"fullName"];
NSString *tmp = [self primitiveFullName];
[self didAccessValueForKey:#"fullName"];
if (!tmp) {
tmp = [NSString stringWithFormat:#"%# %#", [self firstName], [self lastName]];
[self setPrimitiveFullName:tmp];
}
return tmp;
}
- (void)setFirstName:(NSString *)aFirstName
{
[self willChangeValueForKey:#"firstName"];
[self setPrimitiveFirstName:aFirstName];
[self didChangeValueForKey:#"firstName"];
[self setPrimitiveFullName:nil];
}
- (void)setLastName:(NSString *)aLastName
{
[self willChangeValueForKey:#"lastName"];
[self setPrimitiveLastName:aLastName];
[self didChangeValueForKey:#"lastName"];
[self setPrimitiveFullName:nil];
}
+ (NSSet *)keyPathsForValuesAffectingFullName
{
return [NSSet setWithObjects:#"firstName", #"lastName", nil];
}

Resources