How to declare constant values in nsarray in ios - iphone

I had declared constant NSArray like the below way.
static NSArray* const myArray = [NSArray arrayWithObjects:#"obj1",#"obj2",#"ibj3",#"obj4",#"obj5",nil];
But it shows an error "Initiliser elements are Not Compile time constants".
So I declared like this.But I got the error.
Please help This Case.
Thanks.

Since NSArrays are heap-allocated objects, you cannot create them in a static context. You can declare the variables, and then initialize them in a method.
So, you can do this way :-
static NSArray *myStaticArray = nil;
- (void) someMethod
{
if (myStaticArray == nil)
{
myStaticArray = [[NSArray alloc] init...];
}
}
Hope it helps you..

I don't see why you cannot use this to solve your problem. it is 100% constant, because the NSArray is immutable, and it is also 100% static.
GlobalConstant.h file:
#import <Foundation/Foundation.h>
// EDITED : __unused static NSArray *_myGlobalArray;
#interface GlobalConstant : NSObject
+ (NSArray *)myGlobalArray;
#end
GlobalConstant.m file:
#import "GlobalConstant.h"
#implementation GlobalConstant
+ (NSArray *)myGlobalArray {
static NSArray *_myGlobalArray = nil; // EDITED
#synchronized (_myGlobalArray) {
if (_myGlobalArray == nil) {
_myGlobalArray = [NSArray arrayWithObjects:#"1", #"2", nil]; // here is your array...
}
return _myGlobalArray;
}
}
#end
...and your array will be available in every class which includes the GlobalConstant.h file, you can reach the array like
NSArray *_globalArray = [GlobalConstant myGlobalArray];

To create the static array you can make use of the initialize method. This is a special class method that every class has. It is called the first time a class is referenced in any way and before any other code in the class is executed.
static NSArray* myArray = nil;
#implementation SomeClass
+ (void)initialize {
if (self == [SomeClass class]) {
myArray = #[ #"obj1", #"obj2", #"obj3", #"obj4", #"obj5" ];
}
}
// rest of methods
#end

and, to save typing, you can use NSArray* myArray = #[ #"obj1", #"obj2", #"ibj3", #"obj4", #"obj5" ];

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 do I build up a global like integer array?

How do I build up a global like integer array?
I tried variations of the following:
#interface
int *iArray; //this space will vary depending upon need in the implementation
#implementation
...
int iArrayInit[4] = {1,2,3,4};
iArray = iArrayInit;
-bottom line: I need to keep index values in array that I can access easily, and use of [NSArray intValue] maybe to slow.
thanks
If it needs to be static you can declare an NSMutableArray as static in the implementation file and expose static methods to access it. When using an NSArray the values need to be of type id which NSNumber can do. Here is an example which currently is not thread safe.
//.h file
#interface Foo : NSObject
{
}
+(NSArray*)iArray;
+(void)addiArrayValue:(NSNumber*)value;
#end
//.m file
#implementation Foo
static NSMutableArray *_iArray;
+(void)initialize
{
if([Foo class] == self)
{
_iArray = [[NSMutableArray alloc] init];
}
}
+(NSArray*)iArray
{
return [[_iArray copy] autorelease];
}
+(void)addiArrayValue:(NSNumber*)value
{
[_iArray addObject:value];
}
#end
//Use
[Foo addiArrayValue:[NSNumber numberWithInt:10]];
[Foo addiArrayValue:[NSNumber numberWithInt:12]];
NSLog(#"%#", [Foo iArray]);

How do a populate an NSArray const? (code not working included)

How do a populate an NSArray const? Or more generically how can I fix my code below to have an array constant (created in Constants.h & Constants.m) to be available to other parts of my code.
Was hoping to be able to access the constant as a static type object (i.e. as opposed to having to create an instance of constants.m and then access it) is this is possible.
I note the approach works OK for a string, but for NSArray the issue is populating the array.
Code:
constants.h
#interface Constants : NSObject {
}
extern NSArray * const ArrayTest;
#end
#import "Constants.h"
#implementation Constants
NSArray * const ArrayTest = [[[NSArray alloc] initWithObjects:#"SUN", #"MON", #"TUES", #"WED", #"THUR", #"FRI", #"SAT", nil] autorelease];
// ERROR - Initializer element is not a compile time constant
#end
The standard approach is to supply a class method that creates the array the first time it is requested and thereafter returns the same array. The array is never released.
A simple, example solution is this:
/* Interface */
+ (NSArray *)someValues;
/* Implementation */
+ (NSArray *)someValues
{
static NSArray *sSomeValues;
if (!sSomeValues) {
sSomeValues = [[NSArray alloc]
initWithObjects:/*objects*/, (void *)nil];
}
return sSomeValues;
}
You can of course fancy this up with GCD instead of using an if:
/* Implementation */
+ (NSArray *)someValues
{
static NSArray *sSomeValues;
static dispatch_once_t sInitSomeValues;
dispatch_once(&sInitSomeValues, ^{
sSomeValues = [[NSArray alloc]
initWithObjects:/*objects*/, (void *)nil];
});
return sSomeValues;
}

Sorting NSDictionary with multiple constraints

I have a NSDictionary collection whose key is a unique id and value is an array with two different objects (FruitClass, ProductClass) and I would like to group the collection such that it's sorted first by ProductClass.productName and then by FruitClass.itemName.
So the final list would look something like:
{apple, butter}
{apple, pie}
{banana, daiquiri}
{banana, smoothie}
{melon, zinger}
where the first item is a FruitClass instance item and second is a ProductClass instance item.
What's the best way to go about doing this? Most of the examples I've come across are done on one key. How do you do it with an NSDictionary that has 2 different object types?
Looking at NSDictionary's's keysSortedByValueUsingSelector,
- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator
I get the impression that you would create the 'compare' method on the class type of the value object. So for multiple field sort, would I have to resort to creating a new object type, 'CombinedClass' which contains FruitClass & ProductClass and implement a 'compare' to make this happen?
FruitClass:
{
NSString *itemName;
}
#end
#interface ProductClass
{
NSString *productName;
}
#end
If there is a data structure that consists of only one fruit and only one product then an array is not really a good option. You can use another class and provide a compare: comparator:
#interface ComboClass : NSObject
{
FruitClass *fruit;
ProductClass *product;
}
#property(nonatomic,retain) FruitClass *fruit;
#property(nonatomic,retain) ProductClass *product;
- initWithFruit:(FruitClass *)f andProduct:(ProductClass *) p;
#end
#implementation ComboClass
#synthesize fruit;
#synthesize product;
- (void) dealloc
{
[fruit release];
[product release];
[super dealloc];
}
- initWithFruit:(FruitClass *)f andProduct:(ProductClass *) p
{
self = [super init];
if (!self) return nil;
self.fruit = f; // some recommend against accessor usage in -init methods
self.product = p;
return self;
}
- (NSComparisonResult) compare:(id) another
{
NSComparisonResult result = [self.fruit.itemName compare:another.fruit.itemName];
if (result == NSOrderedSame)
return [self.product.productName compare:another.product.productName];
else
return result;
}
#end
Alternatively, you might be able to use an NSDictionary with product and fruit key-value pairs, (so you'll end up with dictionaries inside a dictionary). The NSSortDescriptor class can be used to sort arrays using values of key-paths, so it might be another option to explore.
You could add a category to NSArray that would do the comparison and you wouldn't have to create another class.
#interface NSArray ( MySortCategory )
- (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare;
#end
The implementation should be pretty straightforward based on your description.
Edit I got a little miffed that this was marked down with no comment, so I did a full implementation to make sure it would work. This is a little different than your sample, but the same idea.
FruitsAndProducts.h
#interface Fruit : NSObject
{
NSString *itemName;
}
#property(nonatomic, copy)NSString *itemName;
#end
#interface Product : NSObject
{
NSString *productName;
}
#property(nonatomic, copy)NSString *productName;
#end
FruitsAndProducts.m
#import "FruitsAndProducts.h"
#implementation Fruit
#synthesize itemName;
#end
#implementation Product
#synthesize productName;
#end
NSArray+MyCustomSort.h
#interface NSArray (MyCustomSort)
- (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare;
#end
NSArray+MyCustomSort.m
#import "NSArray+MyCustomSort.h"
#import "FruitsAndProducts.h"
#implementation NSArray (MyCustomSort)
- (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare
{
// This sorts by product first, then fruit.
Product *myProduct = [self objectAtIndex:0];
Product *productToCompare = [arrayToCompare objectAtIndex:0];
NSComparisonResult result = [myProduct.productName caseInsensitiveCompare:productToCompare.productName];
if (result != NSOrderedSame) {
return result;
}
Fruit *myFruit = [self objectAtIndex:1];
Fruit *fruitToCompare = [arrayToCompare objectAtIndex:1];
return [myFruit.itemName caseInsensitiveCompare:fruitToCompare.itemName];
}
#end
Here it is in action
// Create some fruit.
Fruit *apple = [[[Fruit alloc] init] autorelease];
apple.itemName = #"apple";
Fruit *banana = [[[Fruit alloc] init] autorelease];
banana.itemName = #"banana";
Fruit *melon = [[[Fruit alloc] init] autorelease];
melon.itemName = #"melon";
// Create some products
Product *butter = [[[Product alloc] init] autorelease];
butter.productName = #"butter";
Product *pie = [[[Product alloc] init] autorelease];
pie.productName = #"pie";
Product *zinger = [[[Product alloc] init] autorelease];
zinger.productName = #"zinger";
// create the dictionary. The array has the product first, then the fruit.
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:zinger, banana, nil], #"zinger banana", [NSArray arrayWithObjects:butter, apple, nil], #"butter apple", [NSArray arrayWithObjects:pie, melon, nil], #"pie melon", nil];
NSArray *sortedKeys = [myDict keysSortedByValueUsingSelector:#selector(customCompareToArray:)];
for (id key in sortedKeys) {
NSLog(#"key: %#", key);
}
Your comparator can work on whatever you throw at it... you can make it treat its two arguments as NSArray objects, if this is what you need. When you put arrays as values into your dictionary, then just use those - no need for another class.
If you want to build a new class anyway (maybe for design reasons) - go for it, but it is not a "must do" here.
Edit: strike out to make clear that only one argument is given - as the other one is the object the selector is called on. Using NSArray will need a class extension, a custom class is much cleaner.