Confusion with sortUsingSelector - objective-c

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.

Related

Search array of NSObjects containing Arrays

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

Custom class NSObject not key value coding compliant [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is my object not key value coding-compliant?
I'm having a dictionary and I want to add keys/values to a custom class, but i always get the error, that the class is not KVC compliant, but the Apple documents state that it should be.
My code:
ContactObject.h:
#interface ContactObject : NSObject
+ (ContactObject *)testAdding;
#end
ContactObject.m:
#implementation ContactObject
- (id)init {
self = [super init];
if (self) {
// customize
}
return self;
}
+ (ContactObject *)testAdding
{
// create object
ContactObject *theReturnObject = [[ContactObject alloc] init];
[theReturnObject setValue:#"Berlin" forKey:#"city"];
[theReturnObject setValue:#"Germany" forKey:#"state"];
return theReturnObject;
}
#end
I think I'm missing something very stupid :)
Please, any help appreciated ...
Greetings,
matthias
Actually to be KVC compliant:
How you make a property KVC compliant depends on whether that property is an attribute, a to-one relationship, or a to-many relationship. For attributes and to-one relationships, a class must implement at least one of the following in the given order of preference (key refers to the property key):
The class has a declared property with the name key.
It implements accessor methods named key and, if the property is mutable, setKey:. (If the property is a Boolean attribute, the getter accessor method has the form isKey.)
It declares an instance variable of the form key or _key.
I don't see any of these three implemented. You need to have at least properties that you are trying to set through KVC, the default NSObject implementation is able to set properties through setValue:forKey: but you must declare them.
You need to declare every property that will be used:
#interface ContactObject : NSObject
#property (nonatomic,copy, readwrite) NSString* city;
#property (nonatomic, copy, readwrite) NSString* state;
+ (ContactObject *)testAdding;
#end
Or use a NSMutableDictionary object.
For example:
NSMutableDictionary* dict= [NSMutableDictionary new];
[dict setObject: #"Berlin" forKey: #"city"];
[dict setObject: #"Germany" forKey: #"state"];
You need to actually declare/implement properties. Key-Value Coding doesn't mean that every NSObject is automatically a key/value dictionary.
In this case you would need to declare:
#property (nonatomic, readwrite, copy) NSString* city;
#property (nonatomic, readwrite, copy) NSString* state;
in your #interface declaration.
ObjC is dynamic in some ways, but it's not really dynamic as far as storage in classes. If you want ContactObject to be KVC-compliant for certain keys, those keys need to exist in the class. The KVC Guide has this to say:
For properties that are an attribute or a to-one relationship, this
requires that your class:
Implement a method named -<key>, -is<Key>, or have an instance
variable <key> or _<key>. Although key names frequently begin with a
lowercase letter, KVC also supports key names that begin with an
uppercase letter, such as URL.
If the property is mutable, then it should also implement -set<Key>:.
Your implementation of the -set<Key>: method should not perform
validation.
The easiest way to accomplish that is to declare the keys you want as properties:
#property (copy, nonatomic) NSString * city;
#property (copy, nonatomic) NSString * state;
You can also declare an ivar and implement accessors yourself, but there's usually no good reason to do it that way -- declared properties will take good care of you.

Is dot syntax or bracket syntax correct for property access?

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];
}
}

Memory semantics of a computed array property?

This is for an app that allows users to tag things. Tags are just strings.
An array of TagHolder objects holds a list of all tags in use in the app, with a boolean telling if the tag is selected, but this is an implementation detail.
The external interface calls for two methods, selectedTags, and setSelectedTags: which return and accept an arrays of strings.
I would like these two methods to work as accessors for a declared property selectedTags.
Now, my question is:
What would be the correct memory management semantics to declare for that property?
The code pattern that I have in mind is this (code not tested, so please bear with typos):
#interface TagInfo : NSObject
#property (strong, nonatomic) NSString *tag;
#property (nonatomic) BOOL selected;
#end
#interface SomeClass : NSObject
#property (memorytype, nonatomic) NSArray *selectedTags;
#end
#implementation TagHolder
- (NSArray *)selectedTags
{
// tagInfoArray is an array of all TagInfo objects
NSPredicate *selPred = [NSPredicate predicateWithFormat: #"selected == YES"];
NSArray *selectedTagInfoObjects = [[self tagInfoArray] filteredArrayUsingPredicate: selPred];
NSArray *selectedTags = [selectedTagInfoObjects valueForKey: #"tag"];
return selectedTags;
}
- (void)setSelectedTags: (NSArray *)selectedTags
{
for (TagInfo *tagInfo in [self tagInfoArray]) {
tagInfo.selected = [selectedTags containsObject: tagInfo.tag];
}
}
#end
What should memorytype be? Obviously not strong or weak, but I think it could be any one of assign, copy or even unsafe_unretained, but which one is the most correct for a computed property with an object value?
I normally use ARC, but I guess the question is the same in an environment with manual retain count.
memorytype is significant only when you #synthesize your property accessors. Since you are providing your own implementation for both the getter and the setter, the things you put in parentheses after #property are ignored; I usually put readonly or readwrite there, just to remind myself of what kind of access is available on these properties.
Your code is correct, it will work without creating memory issues with or without ARC.

Core Data custom accessor doesn't even get called

I've got a Core Data property that I'm trying to set at runtime, with a value derived from another property. However, curiously, the custom accessor I built never even seems to get called.
The property, seasonNameVisible, only gets called from a predicate with terms from a search field, as shown here:
// Add our search predicates
for (NSString *term in searchTerms) {
NSPredicate *searchTermPredicate = [NSPredicate predicateWithFormat:#"(episodeName contains[cd] %#) OR (fromSeason.seasonNameVisible contains[cd] %#) OR (fromSeason.fromSeries.seriesName contains[cd] %#)", term, term, term];
[subPredicates addObject:searchTermPredicate];
}
If I change that property to seasonName, that part of the predicate returns a result just fine, so I'm not suspecting the predicate or any of the other search code.
My plan is to derive the seasonNameVisible NSString from seasonName at runtime. So, I've modified the Season NSManagedObject subclass to override the accessor and setter, using primitive accessors. But as far as I can tell, my accessor never gets called.
Here is the header/interface:
//
// Season.h
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Episode, Series;
#interface Season : NSManagedObject
#property (nonatomic, retain) NSNumber * seasonIndex;
#property (nonatomic, retain) NSString * seasonName;
#property (nonatomic, retain) NSString * seasonNameVisible;
#property (nonatomic, retain) NSSet *episodes;
#property (nonatomic, retain) Series *fromSeries;
#property (nonatomic, retain) NSString * primitiveSeasonName;
#property (nonatomic, retain) NSString * primitiveSeasonNameVisible;
#end
#interface Season (CoreDataGeneratedAccessors)
- (void)addEpisodesObject:(Episode *)value;
- (void)removeEpisodesObject:(Episode *)value;
- (void)addEpisodes:(NSSet *)values;
- (void)removeEpisodes:(NSSet *)values;
#end
// my additions
#interface Season (PrimitiveAccessors)
- (NSString *)primitiveSeasonName;
- (NSString *)primitiveSeasonNameVisible;
#end
...and the implementation:
//
// Season.m
//
#import "Season.h"
#import "Episode.h"
#import "Series.h"
#implementation Season
#dynamic seasonIndex;
#dynamic seasonName;
#dynamic seasonNameVisible;
#dynamic episodes;
#dynamic fromSeries;
// my additions
#dynamic primitiveSeasonName;
#dynamic primitiveSeasonNameVisible;
- (NSString *)seasonNameVisible
{
NSString *visible;
[self willAccessValueForKey:#"seasonNameVisible"];
visible = [self primitiveValueForKey:#"seasonNameVisible"];
[self didAccessValueForKey:#"seasonNameVisible"];
if (visible != nil) {
return visible;
} else {
[self willAccessValueForKey:#"seasonName"];
visible = [[self primitiveValueForKey:#"seasonName"] substringFromIndex:2];
[self didAccessValueForKey:#"seasonName"];
[self setSeasonNameVisible:visible];
return visible;
}
}
- (void)setSeasonNameVisible:(NSString *)seasonNameVisible
{
[self willChangeValueForKey:#"seasonNameVisible"];
[self setPrimitiveValue:seasonNameVisible forKey:#"seasonNameVisible"];
[self didChangeValueForKey:#"seasonNameVisible"];
}
#end
I've read Apple's docs, and searched around for help with custom accessor methods on StackOverflow, and I think I have the code right (this is the first time I've ever tried to use primitive accessors, or to override an NSManagedObject method, so I'm a tad out of my usual depth), but even when I put a breakpoint on it, it never seems to get called.
You're asking core data to fetch based on a lazily loaded attribute. I dont think this is going to work. You either need to set your seasonNameVisible when you set the season name or, which may make more sense, separate out the storage of your season name into whatever is the prefix (that you are removing to give the visible name) and whatever is the real name.
After the additional information in the comments, I would advise the following:
split your season into two attributes, a season number (int) and season name
sort your fetch request on season number
section name key path is a new read-only property on your object, which returns a string made of the number and name
The error you are seeing in your comment is normal when altering a fetch request used with an FRC. Delete the app from the simulator and re-build and it will go away, or use a nil cache while developing. The FRC stores its cache permanently (eg between runs) so any changes upset it.
Section name key path can be any key path or property name you like, as long as the sorting is the same. From the docs for NSFetchedResultsController:
sectionNameKeyPath
A key path on result objects that returns the section name. Pass nil to indicate that the controller should generate a single section.
The section name is used to pre-compute the section information.
If this key path is not the same as that specified by the first sort descriptor in fetchRequest, they must generate the same relative orderings. For example, the first sort descriptor in fetchRequest might specify the key for a persistent property; sectionNameKeyPath might specify a key for a transient property derived from the persistent property.
So, you'd have a Season object with two persistent attributes, seasonNumber and seasonName. You'd sort your fetch request by season number. Your section name key path (for a fetch presumably on episodes, which have a season relationship) would be #"season.seasonSectionName", implemented as follows - no changes in your managed object model, just changes to your Season object:
Season.h:
#property(nonatomic,readonly) NSString *seasonSectionName;
Season.m:
-(NSString*)seasonSectionName
{
return [NSString stringWithFormat:#"%d - %#",self.seasonNumber,self.seasonName];
}
All you're really doing is decorating the season number with another property.