I have an Array full of PhRecords. For simplicity sake, let us consider the structure of object is as follows:
#interface PhRecord : NSObject
#property (nonatomic, strong) NSArray *PhName; //Person's name
#property (nonatomic, strong) NSArray *PhNumbers; //Person will have 2/3 contact numbers
#property (nonatomic, strong) NSArray *PhTypes; //The types of the contact numbers
#end
There is a property in my class which goes through the phone book and collects the names and phone numbers in an array in the format specified above. Let's say the array is the following
#property (nonatomic, strong) NSArray *allContacts;
Also, I have method to get all contacts as PhRecords with the following method
- (NSArray *)getAllContacts;
I have a method where if I give the contact number, it will find the name and type of the contact.
//Assume that both string1 and string2 don't have (,),*,#,+ and "<white space>"
- (void)findContactByPhoneNumber:(NSString *)phNum {
NSString *string1 = phNum;
NSArray *contacts = [self getAllContacts];
for(SDPhoneRecord *record in contacts) {
for(int j=0;j<record.PhNumbers.count;j++) {
NSString *string2 = [[record.PhNumbers objectAtIndex:j];
if([string2 rangeOfString:string1].location!=NSNotFound) {
NSLog(#"Name:%#,Type:%#",record.PhName,[record.PhTypes objectAtIndex:j];
}
}
}
}
As you can see, this search has time complexity of O(n^2). Is it possible to do a O(1) lookup? If I have to use predicates, how can I use them with this kind of requirement where a "range" of string has to be compared with the string passed argument?
To improve the "big O" you need to eliminate loops, not simply hide them. This generally implies using some sort of "look at" mechanism, vs a "look up" mechanism -- a mechanism that uses, eg, a hash table to locate item. The main such mechanism in Objective-C is the NS(Mutable)Dictionary, which internally contains a hash table.
In some cases it's possible to employ properties of the data to improve search efficiency, but absent that the hash table is usually the best (and most general) approach.
Use the NSArray objectsPassingTest where the test is if the phone number attribute is equal to the provided string
Related
I have a class 'Membership' for which i create 10 member objects in my VC
#property (nonatomic,strong) Membership *member1;
#property (nonatomic,strong) Membership *member2;
..
#property (nonatomic,strong) Membership *member10;
and these are held in an
NSArray *membersArray;
which is periodically saved to file. In places my code needs to deal with those objects generically. How to select them is the problem
for (int idx=0; idx<10; idx++ {
NSString *str = [NSString stringWithFormat:#"self.member%d.name",idx];
str = nameField.text;
}
// further code edited out due to comment request for clarification
doesn't show an error but obviously isn't going to work. str holds the name, but the object itself doesn't.
How is it done?
I could write a function for each member and send program flow through switch cases, and that may be OK if there were only 2 or 3 members but for 10 that's just ungainly
Don't declare separate properties for each Membership. Instead, make the membersArray a property, and then access individual ones with subscripts, remembering that array subscripts are 0-based--in other words, your current member1 can be accessed at self.membersArray[0].
I've seen a lot of people use NSDictionary for JSON parsing:
//ViewController.m
NSString* forename = [jsonDict valueForKey:#"forename"];
NSString* surname = [jsonDict valueForKey:#"surname"];
But I've also people creating custom NSObjects from a NSDictionary.
//JSONObject.h
#interface JSONObject : NSObject
#property (nonatomic) NSString* forename;
#property (nonatomic) NSString* surname;
#end
//JSONObject.m
#implementation JSONObect
#synthesize forename = _forename;
#synthesize surname = _surname;
#end
//ViewController.m
JSONObject* jsonObject = [[JSONObject alloc] init];
[jsonObject setForename:[jsonDict valueForKey:#"forename"]];
[jsonObject setSurname:[jsonDict valueForKey:#"surname"]];
And then store these in a NSMutableArray:
NSMutableArray* jsonObjectsArray = [NSMutableArray arrayWithCapacity:20];
[jsonObjectsArray addObject:jsonObject];
Which can be accessed later if needed.
In my case, I have a UITableView that gets it's data from JSON. The data is used at least once but most likely will be used more (eg. on device rotation). The JSON data shouldn't be permanently stored to file as it is updated regularly and is downloaded every time the app launches.
Should I use a custom NSObject or a NSDictionary in my scenario?
One argument for using a custom Object is that it is a few short steps away from using a NSManagedObject, which would let you leverage Core Data to manage your object graph.
The argument for using the NSDictionary is that it's simpler and easier to understand, and you define fewer "minor" classes (and associated h/m files), so less to manage in a project. Also a lot easier to edit/extend in a project "in flux".
I was having some confusion when the book started talking about alphabetizing elements in the array using the sort and compareNames: method. How is the argument for compareNames obtained when the method sort is called? And how do the elements actually get alphabetize when all that's returned is a type of NSComparisonResult?
#import <Foundation/Foundation.h>
#interface AddressCard : NSObject
#property (copy, nonatomic) NSString *name, *email;
-(NSComparisonResult) compareNames: (id) element;
#end
#implementation AddressCard
#synthesize name, email;
-(NSComparisonResult) compareNames:(id)element {
return [name compare: [element name]];
}
#end
#import "AddressCard.h"
#import <Foundation/Foundation.h>
#interface AddressBook : NSObject
#property (nonatomic, copy) NSString *bookName;
#property (nonatomic, strong) NSMutableArray *book;
-(void) addCard: (AddressCard *) myCard;
-(void) sort;
#end
#implementation AddressBook
#synthesize book, bookName;
-(void) sort {
[book sortUsingSelector: #selector(compareNames:)];
}
A NSComparisonResult is just one of NSOrderedAscending, NSOrderedSame, NSOrderedDescending.
The method compareNames is responsible of the true comparison. In this case, since you are comparing strings, the method just rely on already-implemented compare method of NSString. The result gives information about the comparison between two strings according to the alphabetical order.
Method sortUsingSelector of NSMutableArray is a useful method to sort custom types of data (you can appreciate better if you try to sort custom objects according to custom criteria). It accepts a selector, which means that every time it needs to compare two object, the method specified by the selector is called.
For what I remember you are not allowed to know the method sortUsingSelector internally uses (quick sort / heap sort / bubble sort...), what you need to know is that object are ordered using the criteria specified by the implementation of the method you pass with the selector.
The compareNames: method is repeatedly called by the sorting method (sortUsingSelector:) for every pair of elements it needs to compare; it supplies the arguments. Exactly which pairs of elements it compares to sort the array depends on the sorting algorithm. The Apple docs do not mention which method is used but QuickSort is a fairly common one. If you look at the Wikipedia page you should probably be able to see how by repeatedly comparing pairs of items you can end up with the complete array sorted.
Suppose I have
#interface A : NSObject
#property (nonatomic, strong) NSMutableArray *array;
#end
Later on in another class B, I want to access that array, to check how many items are in it. I can do one of two things in B (a is an instance of A):
Option 1
[a.array count]
Option 2
[[a array] count];
Which option is the best way to do this? Is option 2 the right way to access the array when using [a array] as the getter method?
both are the same if you have synthesized the array. in first one you just call the property and in 2nd one you are calling the getter method which was generated by #synthesize action.
and sure the 2nd option is the right way as #synthesize makes two methods
1- getter that is same as the property name
2- setter that is add set with property name at start with first letter captial like setArray.
There is no difference between the two if you have synthesized the array, as The Saad said. However, I recommend bracket syntax as to remain consistent in all your method calling as all other Objective-C methods (aside from functions from C) use bracket syntax to be called.
There's no difference until you decide to rename the generated getter/setter methods and the message is likely to become invalid.
For the public instance variables you can skip the accessor methods (both property and method styles) and use the structure dereference operator:
#interface A : NSObject
{
NSMutableArray *array;
}
#property (nonatomic, strong) NSMutableArray *array;
#end
classA.m
[self->array count];
classB.m
[a->array count];
Doing this, you waive the convenience of both operation and memory management optimizations which you have using properties (in both access styles) with the different attributes, see more.
As example for the NSString property
#property (readwrite, copy) NSString *sVar;
the generated setter looks like this:
-(void)setSVar:(NSString*)inSVar
{
if (self->sVar != inSVar)
{
[self->sVar release];
self->sVar = [inSVar copy];
}
}
Is there any generic implementation which converts any Object into NSDictionary, sets all variable names as keys and values as dictionary values?
In order to achieve your objective, you can use Key-Value Coding. This protocol provides a mechanism to set values of object properties based on the names of the properties represented as NSString's rather than calling the accessors directly.
In order for it to work, you need to have defined your objects with accessors that follow the naming conventions (easy enough using properties). You can see the NSKeyValueCoding protocol guide here:
http://bit.ly/es6kyH
And the Key-Value Coding programming guide here:
http://bit.ly/fBY3Qa
You'll still have to do the iteration, but it's a good start.
Solved using SBJSONParser, converted NSObject to JSON Representation and then fetched NSDictionary out of it.
The perfect way to do this is by using a library for serialization/deserialization
many libraries are available but one i like is
JagPropertyConverter
https://github.com/jagill/JAGPropertyConverter
it can convert your Custom object into NSDictionary and vice versa
Assuming
#interface Person : NSObject
#property (nonatomic, retain) NSNumber * age
#property (nonatomic, retain) NSString * address
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * cellNo;
#end
JAGPropertyConverter *converter = [[JAGPropertyConverter alloc]init];
converter.classesToConvert = [NSSet setWithObjects:[Person class], nil];
Person *person = [[Person alloc]init];
person.name = #"name";
person.address = #"address";
person.age = #27;
person.cellNo = #"XXXXXXXXXX";
//For Object to Dictionary
NSDictionary *dictPerson = [converter convertToDictionary:person];
//For Dictionary to Object
Person *person = [[Person alloc]init];
[converter setPropertiesOf:person fromDictionary:dictPerson];
No, you could have everything in your class, e.g. references to other objects and primitives. NS-Dictionary can serialize itself to a NSString and NSString can recreate the dictionary from the string. Best will be you supply your own methods to serialize it.