I am trying to implement a singleton which contains an NSMutableArray* what I've done so far is below.
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject{
NSMutableArray* ClassArray;
}
#property NSMutableArray* ClassArray;
+(Singleton*) getInstance;
- (void) SetClassArray:(NSMutableArray *)InputClassArray;
- (NSMutableArray*) GetClassArray;
Singleton.m
#import "Singleton.h"
#implementation Singleton
#synthesize ClassArray;
static Singleton *singletonInstance;
+ (Singleton*)getInstance{
if (singletonInstance == nil) {
singletonInstance = [[super alloc] init];
}
return singletonInstance;
}
- (void) SetClassArray:(NSMutableArray *)InputClassArray{
ClassArray = InputClassArray;
}
- (NSMutableArray*) GetClassArray{
return ClassArray;
}
#end
what I'm wondering is where does [[NSMutableArray alloc]init]; go? or do i not need it. Also when ClassArray is initialised i want some default values, (the return from another function,[DatabaseFunctions GetClassDefaultArray] ) again where does this go?. I'm assuming the line below singletonInstance = [[super alloc] init]; however it doesn't accept ClassArray.
I have an application consisting of four view controllers, what I need is an nsmutablearray that can be accessed and written to from any of these views. There are three others in total.
Thanks
I'm wondering is where does [[NSMutableArray alloc]init]; go? or do i not need it
That depends on what you expect in your getter. Is reasonable for your use case to return nil in GetClassArray?
You could guard against it by returning an empty array if it is nil:
- (NSMutableArray*) GetClassArray{
if ( ! ClassArray ) {
ClassArray = [[NSMutableArray alloc] init];
}
return ClassArray;
}
i want some default values
You can populate your array as you see fit whenever you want, the best place to start would probably be your init method:
+ (Singleton*)getInstance{
if (singletonInstance == nil) {
singletonInstance = [[super alloc] init];
NSMutableArray *array = ...;
[singletoneinstance SetClassArray:array];
}
return singletonInstance;
}
As a side note, I would recommend reading up on some naming conventions so you don't mixed up between class names and variable names in the future.
Related
I'm learning objective-C and it's my first post, be gentle. I have searched the site and re-read my learning material but not sure what I'm not understanding/doing right.
my objective is to add a method to an existing class that returns an NSArray of the top three most valuable "stocks" in an array. I have a working "stock" class, with a "valueInDollars" method, and a "portfolio" class that can hold instances of my stock class. I am using NSSortDescriptor to sort my NSMutableArray of stocks by their valueInDollars then return a copy of the mutable array with the top three values. here is my BNRStockHolding.h file:
#import <Foundation/Foundation.h>
#class BNRPortfolio;
#interface BNRStockHolding : NSObject
{
// declare instance variables
float _purchaseSharePrice;
float _currentSharePrice;
int _numberOfShares;
// add an instance variable that will allow us to print out the solution with less code
NSString *_stockName;
}
// create a holder to use in the sorting method of BNRPortfolio
#property (nonatomic, weak) BNRPortfolio *holder;
// accesor methods declared
- (float)purchaseSharePrice;
- (void)setPurchaseSharePrice:(float)p;
- (float)currentSharePrice;
- (void)setCurrentSharePrice:(float)c;
- (int)numberOfShares;
- (void)setNumberOfShares:(int)n;
- (NSString *)stockName;
- (void)setStockName:(NSString *)s;
- (void)addYourselfToArray:(NSMutableArray *)theArray;
// instance methods below are defined in .m file as they are the result of
// a mathematical equation using the instance variables above
- (float)costInDollars;
- (float)valueInDollars;
#end
And my BNRPortfolio.h file:
#import <Foundation/Foundation.h>
// use #class so we can declare that this portfolio class will access the
// 'valueInDollars' instance variable from the BNRStockHolding class
#class BNRStockHolding;
#interface BNRPortfolio : NSObject
#property (nonatomic, copy) NSArray *holdings;
#property (nonatomic, copy) NSArray *mostValuableHoldings;
- (float)totalValue;
- (void)addHolding:(BNRStockHolding *)h;
- (void)removeHolding:(BNRStockHolding *)r;
#end
And BNRPortfolio.m file:
#import "BNRPortfolio.h"
#import "BNRStockHolding.h"
#interface BNRPortfolio ()
{
NSMutableArray *_holdings;
NSMutableArray *_mostValuableHoldings;
}
#end
#implementation BNRPortfolio
- (void)setHoldings:(NSArray *)s
{
_holdings = [s mutableCopy];
}
- (NSArray *)holdings
{
return [_holdings copy];
}
- (void)setMostValuableHoldings:(NSArray *)m
{
_mostValuableHoldings = [m mutableCopy];
}
- (NSArray *)mostValuableStocks;
{
NSSortDescriptor *highToLow = [NSSortDescriptor sortDescriptorWithKey:#"holder.valueInDollars" ascending:NO];
[_holdings sortUsingDescriptors: #[highToLow]];
for (int i = 0; i < 3; i++) {
for (BNRStockHolding *m in _holdings) {
[_mostValuableHoldings addObject:m];
break;
}
}
return [_mostValuableHoldings copy];
}
- (void)addHolding:(BNRStockHolding *)h
{
// is the holdings array nil?
if (!_holdings) {
// create the array
_holdings = [[NSMutableArray alloc] init];
}
// add the holding in to the holdings array
[_holdings addObject:h];
}
// describe how removeHolding works
- (void)removeHolding:(BNRStockHolding *)r
{
if (r) {
[_holdings removeObject:r];
}
}
- (float)totalValue
{
// add the currentValue values of all holdings in the holdings array by iterating through
// it and returning the sum
float sum = 0;
for (BNRStockHolding *h in _holdings) {
sum += [h valueInDollars];
}
return sum;
}
// change the description property to return an NSString with the total value of the portfolio
- (NSString *)description
{
return [NSString stringWithFormat:#"<stock portfolio with a total value of %.2f>", self.totalValue];
}
#end
Some of you may recognize the names of the classes as I am following the Big Nerd Ranch guide on Objective-C and I have not renamed my classes. I have already searched the dedicated BNR forums for a solution and posted my issue there but to no avail and the solution is not given in the book. I desperately want to learn and understand exactly why this isn't working so please be detailed with your answer. Thank you so much in advance!
The first line of your mostValuableStocks method should be
_mostValuableHoldings = [[NSMutableArray alloc] init];
Which is to say that I don't see any code that alloc/inits that array.
Try to change
NSSortDescriptor *highToLow =
[NSSortDescriptor sortDescriptorWithKey:#"holder.valueInDollars" ascending:NO];
to
NSSortDescriptor *highToLow =
[NSSortDescriptor sortDescriptorWithKey:#"valueInDollars" ascending:NO];
or
NSSortDescriptor *highToLow =
[NSSortDescriptor sortDescriptorWithKey:#"SELF.valueInDollars" ascending:NO];
You could just do:
- (NSArray *)mostValuableStocks
{
return [[array sortedArrayUsingComparator:^(BNRStockHolding *h1, BNRStockHolding *h2) {
return [#([h1 valueInDollars]) compare:#([h2 valueInDollars])];
}] subarrayWithRange:(NSRange){0, 3}];
}
to help those having the same issue, here is the portion I changed to fix things in the BNRPortfolio.m file:
- (NSArray *)mostValuableHoldings;
{
if (!_mostValuableHoldings) {
_mostValuableHoldings = [[NSMutableArray alloc] init];
}
NSSortDescriptor *highToLow = [NSSortDescriptor sortDescriptorWithKey:#"valueInDollars" ascending:NO];
[_holdings sortUsingDescriptors: #[highToLow]];
for (int i = 0; i < 3; i++) {
[_mostValuableHoldings addObject:_holdings[i]];
}
return [_mostValuableHoldings copy];
}
I have declared a NSMutableArray as a singleton; when I try to check for the array count, the app crashes! Here is the code:
// clear array that holds selected servcies
SingletonArrayOfSelectedRows *arrayOfSelectedRows = [SingletonArrayOfSelectedRows sharedArrayOfSelectedRows];
if([arrayOfSelectedRows count] > 0)
[arrayOfSelectedRows removeAllObjects];
This code is the same code I have found all over SO and Google. Using XCode5, I have checked to make sure the singleton is allocated (and it is), and there is a valid count (0) for the singleton.
UPDATE
Here is the code for the singleton.h file:
#interface SingletonArrayOfSelectedRows : NSMutableArray {
}
#property (nonatomic, retain) NSMutableArray *arrayOfSelectedRows;
+ (id)sharedArrayOfSelectedRows;
#end
Here is the code for the singleton.m file:
#implementation SingletonArrayOfSelectedRows {
}
#synthesize arrayOfSelectedRows; // rename
// sharedSelectedCellIndexes
+ (id)sharedArrayOfSelectedRows {
static dispatch_once_t dispatchOncePredicate = 0;
__strong static id _sharedObject = nil;
dispatch_once(&dispatchOncePredicate, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-(id) init {
self = [super init];
if (self) {
arrayOfSelectedRows = [[NSMutableArray alloc] init];
}
return self;
}
#end
Don't subclass NSMutableArray to do this. NSMutableArray is a class cluster. All of the actual array implementation is inside subclasses of NSMutableArray. If you subclass NSMutableArray then your subclass won't actually implement any array behavior unless you write it yourself.
According to the documentation :
Any subclass of NSArray must override the primitive instance methods count and objectAtIndex:.
Since you are subclassing NSMutableArray you will need to override the following NSMutableArray primitive methods as well:
insertObject:atIndex:
removeObjectAtIndex:
addObject:
removeLastObject
replaceObjectAtIndex:withObject:
I use the following code to create a public static array in C#
public class A{
public static array[] obj;
}
I have another class B.
From class B I call
A.ArrayName and I get the array I use in class A.
I wanted to know, what is the equivalent of this in objective C
There is no special syntax for this. You just define a class method to return the static array.
For example:
#implementation A // note this is in the implementation
static NSArray *array;
+ (NSArray *)array
{
if (!array)
array = [[NSArray alloc] init];
return array;
}
#end
Or for messier code, but slightly better performance (a good idea in a tight loop, but usually not worthwhile):
#implementation A
static NSArray *array;
+ (void)initialize // this method is called *once* for every class, before it is used for the first time (not necessarily when the app is first launched)
{
[super initialize];
array = [[NSArray alloc] init];
}
+ (NSArray *)array
{
return array;
}
#end
To access it from class B you just do:[A array]
I want to propose using a Category on NSArray. I changed your requirement a bit to use an NSMutableArray as shared object.
interface file:
#import <Foundation/Foundation.h>
#interface NSArray (StaticArray)
+(NSMutableArray *)sharedInstance;
#end
implementation file
#import "NSArray+StaticArray.h"
#implementation NSArray (StaticArray)
+(NSMutableArray *)sharedInstance{
static dispatch_once_t pred;
static NSMutableArray *sharedArray = nil;
dispatch_once(&pred, ^{ sharedArray = [[NSMutableArray alloc] init]; });
return sharedArray;
}
#end
Now you can use it as:
[[NSArray sharedInstance] addObject:#"aa"];
[[NSArray sharedInstance] addObject:#"bb"];
[[NSArray sharedInstance] addObject:#"cc"];
and somewhere else:
NSLog(#"%#", [NSArray sharedInstance]);
I'm having a bit of trouble with memory leaks in my objective c code. Could anyone take a look and let me know what they think?
NSStringArray.h
#interface NSStringArray : NSObject {
NSMutableArray *realArray;
}
#property (nonatomic, assign) NSMutableArray *realArray;
-(id)init;
-(void)dealloc;
#end
NSStringArray.m
#import "NSStringArray.h"
#implementation NSStringArray
#synthesize realArray;
-(id)init {
self = [super init];
if ( self != nil ) {
realArray = [[[NSMutableArray alloc] init] retain];
}
return self;
}
-(void)dealloc {
[realArray release];
realArray = nil;
[super dealloc];
}
Factory.m
+(NSStringArray *)getFields:(NSString *)line {
//Divides the lines into input fields using "," as the separator.
//Returns the separate fields from a given line. Strips out quotes & carriage returns.
line = [line stringByReplacingOccurrencesOfString:#"\"" withString:#""];
line = [line stringByReplacingOccurrencesOfString:#"\r" withString:#""];
NSStringArray *fields = [[NSStringArray alloc] init];
for (NSString *field in [line componentsSeparatedByString:#","]) {
[fields.realArray addObject:field];
[field release];
}
return [fields autorelease];
}
The Leaks tool is saying that the leak occurs when fields is allocated, and when I am adding field string to the fields array.
Also, this function is getting called each line of a file that I'm parsing.
Any tips would be helpful.
Thanks!
This line does a double retain:
realArray = [[[NSMutableArray alloc] init] retain];
it is enough
realArray = [[NSMutableArray alloc] init];
In this piece of code, you break the memory management rules.
for (NSString *field in [line componentsSeparatedByString:#","]) {
[fields.realArray addObject:field];
[field release];
}
You do not own the object pointed at by field so you must not release it.
You have overreleased field so the last object to release it (the autorelease pool in your case) is releasing an already dealloc'd object.
From the docs:
An allocation message does other important things besides allocating
memory:
It sets the object’s retain count to one (as described in “How Memory
Management Works”).
Therefore, you don't need to retain something that you've just alloc'ed.
Adding to Felz answer above. Use self.realArray when allocating array
self.realArray = [[NSMutableArray alloc] init];
Because you have created a property for the array so it is better to use "self"
You could also take advantage of the properties in objective C to make
more clear and efficient your code:
NSStringArray.h
#interface NSStringArray : NSObject {
}
#property (nonatomic, retain) NSMutableArray *realArray;
#end
NSStringArray.m
#import "NSStringArray.h"
#implementation NSStringArray
#synthesize realArray = _realArray;
-(id)init {
self = [super init];
if (self) {
self.realArray = [NSMutableArray array];
}
return self;
}
-(void)dealloc {
[_realArray release];
[super dealloc];
}
Now, with the modifier retain of the property realArray you can use
[NSMutableArray array] that return an autorelease mutable array.
The retain properties manage the retain/release stuff by themselves.
You don't need to use the realArray = nil; line. You've already deallocated
the property.
Hope this can help.
I'm new to Objective-c. For learning purposes I'm trying to build something like a phonebook. So I'll have a class called Person that will have some properties (name, phone, etc).
Right now I'm not preoccupied about persistence. But, I need something to "hold" Person objects. So I thought about create a class called People, but I don't know how to design it, specially the NSMutableArray that will hold the objects.
What I did was:
PERSON.H
#interface Person : NSObject {
NSString *name;
}
#property(readwrite, copy) NSString *name;
#end
PERSON.M
#implementation Person
#synthesize name;
#end
PEOPLE.H
#interface People : NSObject {
NSMutableArray *peopleArray;
}
#property(readwrite, retain) NSMutableArray *peopleArray;
- (void)addPerson:(Person *)objPerson;
#end
PEOPLE.M
#implementation People
#synthesize peopleArray;
- (id)init {
if (![super init]) {
return nil;
}
peopleArray = [[NSMutableArray alloc] retain];
return self;
}
- (void)addPerson:(Person *)objPerson {
[peopleArray addObject:objPerson];
}
PHONEBOOK.M
...
Person *pOne = [[Person alloc] init];
pOne.name =#"JaneDoe";
People *people = [[People alloc] init];
[people addPerson:pOne];
When I try to use this code, I receive an error:_method sent to an uninitialized mutable array object.
So, since I'm a newbie, probably the way that I did isn't the best/correct one. So, how do I do this?
Two things wrong with your initialiser for people. It should look more like this:
- (id)init {
self = [super init]; // always assign the result of [super init] to self.
if (!self) {
return nil;
}
peopleArray = [[NSMutableArray alloc] init]; // use init not retain.
return self;
}
Because you're not calling init on the NSMutableArray when you create your peopleArray. Try calling:
peopleArray = [[NSMutableArray alloc] init];
instead. You need not retain it unless you say for instance, did this:
peopleArray = [[NSMutableArray array] retain];
For reasons why, see the rules for memory management. These rules are very important for any iPhone or Mac developer to understand, and quite frankly, are simple enough that there's no excuse. :)
In People.m you probably meant to write
peopleArray = [[NSMutableArray alloc] init];
instead of
peopleArray = [[NSMutableArray alloc] retain];