Sorting global data alphbetically - iphone

I am storing the parsed xml values as Global data in Mutable Array some thing like this...
.h file
#interface GlobalData : NSObject {
NSMutableArray *array;
}
#property(nonatomic,retain) NSMutableArray *array;
(id)sharedData;
In .m file
static GlobalData *sharedGlobalData = nil;
#implementation GlobalData
#synthesize array;
+(id)sharedData{
#synchronized(self) {
if(sharedGlobalData == nil)
{
sharedGlobalData=[[GlobalData alloc] init];
sharedGlobalData.boats=[[NSMutableArray alloc] init];
}
}
return sharedGlobalData;
}
(id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if(sharedGlobalData == nil) {
sharedGlobalData = [super allocWithZone:zone];
return sharedGlobalData;
}
}
return nil;
}
I am passing the value of array to a Table view and displaying it as a table. Now i want to sort this array alphbetically from A-Z and pass it to table view.How can i do this???... Plz help

Got it by using NSSortDescriptor....
something like this,
NSSortDescriptor *alphaDesc = [[NSSortDescriptor alloc] initWithKey:#"boatName" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
[[data boats] sortUsingDescriptors:[NSMutableArray arrayWithObjects:alphaDesc, nil]];

Related

Initialize properties in Singletons in objective-c

So I'm kind of unsure about something. What I want is one class to know about the data through all my different view controllers. This one class should have an array of my objects so that if I have a detailViewController, I would just be looking at one instance in my array that the DataManager would hold. I thought that this DataManager would be a singleton. I followed Apple's documentation on creating a singleton, but now I'm a bit confused on the properties.
static DataManager *sharedDmgr = nil;
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[super allocWithZone:NULL] init];
}
return sharedDmgr;
}
If I want an NSMutableArray property, what is the proper way to initialize it? Do I do something like
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[super allocWithZone:NULL] init];
[self sharedInit];
}
return sharedDmgr;
}
- (void)sharedInit {
// initialize all my properties for the singleton here?
}
Thanks!
Let's say a DataManager object has a NSMutableArray attribute named "array", then your objective is to be able to do [DataManager sharedDataManager].array in all your code.
The way to do it would be to:
Declare the NSMutableArray *array as an attribute on the DataManager.h #interface block.
Declare a #property for that attribute.
On the - [DataManager init] method initialize the mutable array. Something like self.array = [NSMutableArray array];
Then your sharedInstance method would be:
static DataManager *sharedDmgr = nil;
+ (id)sharedInstance {
if (sharedDmgr == nil) {
sharedDmgr = [[DataManager alloc] init];
}
return sharedDmgr;
}
All done. Let me know if you need some example code.
You can use the same lazy initialization pattern for your property getters. So for a mutable array...
#interface DataManager ()
#property (strong, nonatomic) NSMutableArray *array;
#end
#implementation DataManager
#synthesize array=_array;
// shared instance method like #fbernardo's suggestion
- (NSMutableArray *)array {
if (!_array) {
_array = [[NSMutableArray alloc] init];
}
return _array;
}

NSMutableArray within singleton class always returns count 0 / never retains its objects

My simplified singleton looks like this:
#interface MyClass : NSObject {
NSMutableArray * myArray;
}
+ (MyClass*) instance;
#property(nonatomic,retain)NSMutableArray *myArray;
Then in the implementation
static MyClass * myinstance;
#synthesize myArray;
+ (MyClass*) instance {
if(myinstance == nil)
myinstance = [[MyClass alloc] init];
return myinstance;
}
- (id) init {
if(self = [super init]) {
myArray = [[NSMutableArray alloc] initWithCapacity:2];
[myArray addObject:#"Trauma"];
}
return self;
}
However when I try to access it for a tableview this always returns 0:
[[[MyClass instance] myArray] count];
Little unsure about what I'm doing wrong
The method that returns the instance of your singleton is named +instance, but when attempting to access your singleton, you are using +myinstance. Your instance of MyClass is most likely nil.

How to access a string in a class stored in an array?

I have a string (titleName) stored in a class (newNoteBook) stored in an array (myLibrary). I was trying to access it, but I only get a (null) printed in the log.
What am I doing wrong?
-(void) setupLibrary {
NoteBook *newNoteBook = [[NoteBook alloc] init];
newNoteBook.titleName = #"TEST";
NSLog(#"titleName:%#", newNoteBook.titleName); // this prints TEST in the log
[myLibrary addObject:newNoteBook];
NSLog(#"titleName:%#", [[self.myLibrary objectAtIndex:0] titleName]); // this prints (null) in the log)
}
There is nothing fancy in my class... simply:
#interface NoteBook : NSObject {
NSString *titleName; }
#property (nonatomic, retain) NSString *titleName;
#end
#implementation NoteBook
#synthesize titleName;
Try this
NSLog(#"titleName:%#", ((NoteBook *)[self.myLibrary objectAtIndex:0]).titleName);
Possible reasons:
myLibrary (the instance variable) is nil;
self.myLibrary is nil or its backing instance variable isn’t myLibrary;
[self.myLibrary objectAtIndex:0] is not the same object as newNoteBook because there was at least one other element in self.myLibrary.
Edit: you need to create a new mutable array and assign it to your property/instance variable myLibrary:
self.myLibrary = [NSMutableArray array];
or
myLibrary = [[NSMutableArray alloc] init];
Where you should this depend on how your class is used. If an instance of your class should always have valid myLibrary, a good place to do that is in -init:
- (id)init {
self = [super init];
if (self) {
myLibrary = [[NSMutableArray alloc] init];
}
return self;
}
Alternatively, if you want to lazily create myLibrary only when -setupLibrary is executed, create it in that method:
-(void) setupLibrary {
self.myLibrary = [NSMutableArray array];
NoteBook *newNoteBook = [[NoteBook alloc] init];
…
}
Don’t forget to release it in your -dealloc method:
- (void)dealloc {
[myLibrary release];
[super dealloc];
}
I think you are not type casting object from array -
NSLog(#"titleName:%#", [(NoteBook*)[self.myLibrary objectAtIndex:0] titleName]);
and you should alloc your array before adding object to it -
myLibrary = [[NSMutableArray alloc] init];
NSLog(#"titleName:%#", [self.myLibrary objectAtIndex:0].titleName);
Is correct as they said before you don't need to cast.

Singleton Class iPhone

Ok, I'm trying to avoid global variables, so I read up on singleton classes.
This is a try to set and read a mutable array, but the result is null.
//Content.h
#interface Content : NSObject {
NSMutableArray *contentArray;
}
+ (Content *) sharedInstance;
- (NSMutableArray *) getArray;
- (void) addArray:(NSMutableArray *)mutableArray;
#end
.
//Content.m
#implementation Content
static Content *_sharedInstance;
+ (Content *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[Content alloc] init];
}
return _sharedInstance;
}
- (NSMutableArray *) getArray{
return contentArray;
}
- (void) addArray:(NSMutableArray *)mutableArray{
[contentArray addObject:mutableArray];
}
#end
And in a ViewController I added #import "Content.h", where I try to call this:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"test",#"foo",#"bar",nil];
Content *content = [Content sharedInstance];
[content addArray:mArray];
NSLog(#"contentArray: %#", [content getArray]);
You need to alloc and init the array first. Personally I'd do it in the init method of the content class like so:
-(id)init{
if(self = [super init]){
…the rest of your init code…
contentArray = [[NSMutableArray alloc] init];
}
return self;
}
You never actually alloc/initialise the contentArray array.

Instantiating Custom Class from NSDictionary

I have a feeling that this is stupid question, but I'll ask anyway...
I have a collection of NSDictionary objects whose key/value pairs correspond to a custom class I've created, call it MyClass. Is there an easy or "best practice" method for me to basically do something like MyClass * instance = [map NSDictionary properties to MyClass ];? I have a feeling I need to do something with NSCoding or NSKeyedUnarchiver, but rather than stumble through it on my own, I figure someone out there might be able to point me in the right direction.
The -setValuesForKeysWithDictionary: method, along with -dictionaryWithValuesForKeys:, is what you want to use.
Example:
// In your custom class
+ (id)customClassWithProperties:(NSDictionary *)properties {
return [[[self alloc] initWithProperties:properties] autorelease];
}
- (id)initWithProperties:(NSDictionary *)properties {
if (self = [self init]) {
[self setValuesForKeysWithDictionary:properties];
}
return self;
}
// ...and to easily derive the dictionary
NSDictionary *properties = [anObject dictionaryWithValuesForKeys:[anObject allKeys]];
There is no allKeys on NSObject. You'll need to create an extra category on NSObject like below:
NSObject+PropertyArray.h
#interface NSObject (PropertyArray)
- (NSArray *) allKeys;
#end
NSObject+PropertyArray.m
#import <objc/runtime.h>
#implementation NSObject (PropertyArray)
- (NSArray *) allKeys {
Class clazz = [self class];
u_int count;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++) {
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
}
free(properties);
return [NSArray arrayWithArray:propertyArray];
}
#end
Example:
#import "NSObject+PropertyArray.h"
...
MyObject *obj = [[MyObject alloc] init];
obj.a = #"Hello A"; //setting some values to attributes
obj.b = #"Hello B";
//dictionaryWithValuesForKeys requires keys in NSArray. You can now
//construct such NSArray using `allKeys` from NSObject(PropertyArray) category
NSDictionary *objDict = [obj dictionaryWithValuesForKeys:[obj allKeys]];
//Resurrect MyObject from NSDictionary using setValuesForKeysWithDictionary
MyObject *objResur = [[MyObject alloc] init];
[objResur setValuesForKeysWithDictionary:objDict];
Assuming that your class conforms to the Key-Value Coding protocol, you could use the following: (defined as a category on NSDictionary for convenience):
// myNSDictionaryCategory.h:
#interface NSDictionary (myCategory)
- (void)mapPropertiesToObject:(id)instance
#end
// myNSDictionaryCategory.m:
- (void)mapPropertiesToObject:(id)instance
{
for (NSString * propertyKey in [self allKeys])
{
[instance setValue:[self objectForKey:propertyKey]
forKey:propertyKey];
}
}
And here's how you would use it:
#import "myNSDictionaryCategory.h"
//...
[someDictionary mapPropertiesToObject:someObject];
If your doing this sort of thing chances are your dealing with JSON and you should probably have a look at Mantle
https://github.com/Mantle/Mantle
You will then get a convenient method dictionaryValue
[anObject dictionaryValue];
Just add category for NSObject for getting dictionaryRepresentation from your custom objects (in my case using in JSON serialization only):
// NSObject+JSONSerialize.h
#import <Foundation/Foundation.h>
#interface NSObject(JSONSerialize)
- (NSDictionary *)dictionaryRepresentation;
#end
// NSObject+JSONSerialize.m
#import "NSObject+JSONSerialize.h"
#import <objc/runtime.h>
#implementation NSObject(JSONSerialize)
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
return [[self alloc] initWithDictionary:aDictionary];
}
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
aDictionary = [aDictionary clean];
self.isReady = NO;
for (NSString* propName in [self allPropertyNames]) {
[self setValue:aDictionary[propName] forKey:propName];
}
//You can add there some custom properties with wrong names like "id"
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
self.isReady = YES;
return self;
}
- (NSDictionary *)dictionaryRepresentation {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *propertyNames = [self allPropertyNames];
id object;
for (NSString *key in propertyNames) {
object = [self valueForKey:key];
if (object) {
[result setObject:object forKey:key];
}
}
return result;
}
- (NSArray *)allPropertyNames {
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableArray *rv = [NSMutableArray array];
unsigned i;
for (i = 0; i < count; i++) {
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
//You can add there some custom properties with wrong names like "id"
//[rv addObject:#"objectID"];
//Example use inside initWithDictionary:
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
free(properties);
return rv;
}
#end
Also, you can see that my solution will not work with custom objects with nested objects or arrays. For Arrays - just change the lines of code in dictionaryRepresentation method:
if (object) {
if ([object isKindOfClass:[NSArray class]]) {
#autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for (id item in (NSArray *)object) {
[array addObject:[item dictionaryRepresentation]];
}
[result setObject:array forKey:key];
}
} else {
[result setObject:object forKey:key];
}
}