Init a NSMutableArray in a singelton that saves as a state - objective-c

Im am using a pattern from the book Learning Cocos2D. I have a GameState class that is a singleton that can be saved as a state. The BOOL soundOn gets init as false the first time the class gest created, but the array levelProgress dosent. I made comments on all the lines on which I have tried to init the array.
The class uses a helper that loads and saves the data.
When i try 1 or 2 i get "instance variable 'levelProgress' accessed in class method" error.
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GameState : NSObject <NSCoding> {
BOOL soundOn;
NSMutableArray *levelProgress;
}
+ (GameState *) sharedInstance;
- (void)save;
#property (assign) BOOL soundOn;
#property (nonatomic, retain) NSMutableArray *levelProgress;
#end
#import "GameState.h"
#import "GCDatabase.h"
#implementation GameState
#synthesize soundOn;
#synthesize levelProgress;
static GameState *sharedInstance = nil;
+(GameState*)sharedInstance {
#synchronized([GameState class])
{
if(!sharedInstance) {
sharedInstance = [loadData(#"GameState") retain];
if (!sharedInstance) {
[[self alloc] init];
// 1. levelProgress = [[NSMutableArray alloc] init];
}
}
return sharedInstance;
}
return nil;
}
+(id)alloc
{
#synchronized ([GameState class])
{
NSAssert(sharedInstance == nil, #"Attempted to allocate a \
second instance of the GameState singleton");
sharedInstance = [super alloc];
// 2. levelProgress = [[NSMutableArray alloc] init];
return sharedInstance;
}
return nil;
}
- (void)save {
saveData(self, #"GameState");
}
- (void)encodeWithCoder:(NSCoder *)encoder {
// 3. levelProgress = [[NSMutableArray alloc] init];
[encoder encodeBool:currentChoosenCountry forKey:#"soundOn"];
[encoder encodeObject:levelProgress forKey:#"levelProgress"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
// 4. levelProgress = [[NSMutableArray alloc] init];
soundOn = [decoder decodeBoolForKey:#"soundOn"];
levelProgress = [decoder decodeObjectForKey:#"levelProgress"];
}
return self;
}
#end
Solution:
*I just added av init method...*
-(id)init {
self = [super init];
if (self != nil) {
levelProgress = [[NSMutableArray alloc] init];
}
return self;
}

Try this (this code may contain syntax or logic errors - I wrote it in notepad):
#interface GameState : NSObject <NSCoding>
#property (nonatomic, readwrite) BOOL soundOn;
#property (nonatomic, retain) NSMutableArray *levelProgress;
+ (GameState *)sharedState;
- (void)writeDataToCache;
#end
//
#implementation GameState
#synthesize soundOn, levelProgress;
#pragma mark - Singleton
static GameState *sharedState = nil;
+ (void)initialize {
static BOOL initialized = NO;
if (!initialized) {
initialized = YES;
if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:#"%#/gameState", pathCache]]) {
NSData *encodedObject = [[NSData alloc] initWithContentsOfFile:[NSString stringWithFormat:#"%#/gameState", pathCache]];
data = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
}
else
data = [[GameState alloc] init];
}
}
+ (GameState *)sharedState {
return sharedState;
}
#pragma mark - Initialization
- (id)init {
if (self = [super init]) { // will be inited while application first run
soundOn = NO;
levelProgress = [[NSMutableArray alloc] init];
return self;
}
return nil;
}
#pragma mark - Coding Implementation
- (void)writeDataToCache { // use this method to save current state to cache
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:self];
if([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:#"%#/GameState", pathCache]])
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:#"%#/GameState", pathCache] error:nil];
[[NSFileManager defaultManager] createFileAtPath:[NSString stringWithFormat:#"%#/GameState", pathCache] contents:encodedObject attributes:nil];
NSLog(#"GameState was saved successfully.");
}
- (void)encodeWithCoder:(NSCoder*)encoder {
[encoder encodeBool:self.soundOn forKey:#"soundOn"];
[encoder encodeObject:self.levelProgress forKey:#"levelProgress"];
}
- (id)initWithCoder:(NSCoder*)decoder {
if ((self = [super init])) {
self.soundOn = [decoder decodeBoolForKey:#"soundOn"];
self.levelProgress = [decoder decodeObjectForKey:#"levelProgress"];
NSLog(#"GameState was inited successfully");
return self;
}
return nil;
}
#end

1 & 2 are the same (and should not work, since levelProgress is an instance variable), 3 and 4 should be encoding/decoding the array, not initializing it anew.

1 and 2 are a mistake - you can't access instance variable without specifying an instance.
You can fix 1 by changing the line to sharedInstance.levelProgress = ....
2 is just a bad idea, you're breaking common convention of initializing using init... methods, it may surprise and cause problems for an other programmer who'll be working on the same code later.
3 and 4 are ok but if loadData fails they will not be executed and the object will be initialized with ordinary init and the array will be nil pointer:
[[self alloc] init];
you should also override init and initialize the properties there.

Related

cocoa - unarchivedObjectOfClass does not call initWithCoder

I am developing a macOS app using objective-C.
I tried to save a NSArray object in Core Data. I write
- (id)reverseTransformedValue:(id)value
{
return [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:value error:nil];
}
in the class that inherits NSValueTransformer.
And one of elements in my NSArray object is not of primary kind(which has properties called courseName and courseInfos), so I conform in this element's class. In this class ,I write:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [[self class] new];
if (self = [super init])
{
self.courseName = [aDecoder decodeObjectForKey:#"courseName"];
self.courseInfos = [aDecoder decodeObjectForKey:#"courseInfos"];
}
return self;
}
When my apps runs, the reverseTransformedValue: method is called, and all elements but that special nonprimary element in my NSArray object are decoded. I put a breakpoint in the initWithCoder: method in that special element's class, and it never runs. I use some tools and find that element is successfully stored in my core data, so its encoding process has no problem.
I Fixed it, here is the solution:
My object is 'Address' (note: it is not NSArray)
Address.h
#interface Address : NSObject <NSSecureCoding>
#property (nonatomic, strong) NSString *street;
#property (nonatomic, strong) NSString *city;
#end
Address.m
#implementation Address
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [self init];
if (self == nil)
{
return nil;
}
self.street = [aDecoder decodeObjectOfClass:[Address class] forKey:#"street"];
self.city = [aDecoder decodeObjectOfClass:[Address class]
forKey:#"city"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.street forKey:#"street"];
[encoder encodeObject:self.city forKey:#"city"];
}
+ (BOOL)supportsSecureCoding
{
return YES;
}
Archive.h
#property (nonatomic, strong) Address *address;
Archive.m
UserDBO *userDBO = [[UserDBO alloc] init];
// Archive
NSError *error = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.address requiringSecureCoding:YES error:&error];
if(error)
{
NSLog(#"archivedDataWithRootObject: %#", error);
}
userDBO.address = data;
// UnArchive
Address *address = [NSKeyedUnarchiver unarchivedObjectOfClass:[Address class] fromData:userDBO.address error:&error];
if(error)
{
NSLog(#"unarchivedObjectOfClass: %#", error);
}
UserDBO.h
#property (nonatomic, strong) NSData *address;

Object loses reference

I have a IKImageBrowserView which has its own controller - BrowserController.h + .m
#interface BrowserController : NSWindowController{
NSMutableArray *_images;
}
#property (strong,nonatomic) IBOutlet IKImageBrowserView *imageBrowser;
-(void)addMultipleImages;
When I run the app for the first time, the staring image loads, but when I click a button to add other images and call a method from another class I don't get any results. I have noticed that my _imageBrowser loses the reference and becomes nil.
How could I solve this issue?
AppDelegate.m
#import "AppDelegate.h"
#import "BrowserController.h"
#implementation AppDelegate{
BrowserController *imageBrowserController;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
imageBrowserController = [BrowserController sharedManager];
}
- (IBAction)doSomething:(id)sender {
[imageBrowserController addMultipleImages];
}
#end
BrowserController.m
#import "BrowserController.h"
#interface myImageObject : NSObject
{
NSString *_path;
}
#end
#implementation myImageObject
/* our datasource object is just a filepath representation */
- (void)setPath:(NSString *)path
{
if(_path != path)
{
_path = path;
}
}
/* required methods of the IKImageBrowserItem protocol */
#pragma mark -
#pragma mark item data source protocol
/* let the image browser knows we use a path representation */
- (NSString *)imageRepresentationType
{
return IKImageBrowserPathRepresentationType;
}
/* give our representation to the image browser */
- (id)imageRepresentation
{
return _path;
}
/* use the absolute filepath as identifier */
- (NSString *)imageUID
{
return _path;
}
#end
#interface BrowserController ()
#end
#implementation BrowserController
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)awakeFromNib{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
- (void)updateDataSource{
[_imageBrowser reloadData];
}
-(NSUInteger) numberOfItemsInImageBrowser:(IKImageBrowserView *)aBrowser{
return [_images count];
};
-(id)imageBrowser:(IKImageBrowserView *)aBrowser itemAtIndex:(NSUInteger)index{
return [_images objectAtIndex:index];
};
- (void)updateDatasource
{
[_imageBrowser reloadData];
}
- (void)addMultipleImages{
myImageObject *p;
p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[_images addObject:p];
[_images addObject:p];
[_imageBrowser reloadData];
}
+ (id)sharedManager {
static BrowserController *sharedMyManager = nil;
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
#end
There is some confusion as to the name of the class where you mention it's called ImageBrowserController at the start of your question and it looks like it's called BrowserController at the end of your question.
The issue is that you allocate _images in awakeFromNib which is never called given the class is created via the singleton pattern (sharedInstance) and not loaded from a .nib file.
Therefore move the code from awakeFromNib into init and dump awakeFromNib:
BrowserController.m:
- (id)init
{
self = [super init];
if (self) {
myImageObject *p = [[myImageObject alloc]init];
[p setPath:[[NSBundle mainBundle]pathForResource:#"Unknown" ofType:#"jpg"]];
_images = [[NSMutableArray alloc]init];
[_images addObject:p];
[self updateDataSource];
}
return self;
}
Further confusion: you have implemented an initWithFrame method. Why?

No visible #interface for 'BNRItemStore' declares the selector 'deleteImageForKey;'

I'm new to objective C and have been learning with the book "IOS Programming Big Nerd Ranch Guide 4th edition". I keep getting a recurring error and I have been working to resolve it for the last few hours. After researching for a bit, I came here. Any help would be greatly appreciated.
"No visible #interface for 'BNRItemStore' declares the selector 'deleteImageForKey;'"
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
#property (nonatomic, readonly) NSArray *allItems;
// Notice that this is a class method and prefixed with a + instead of a -
+ (instancetype)sharedStore;
- (BNRItem *)createItem;
- (void)removeItem:(BNRItem *)item;
- (void)moveItemAtIndex:(NSInteger)fromIndex
toIndex:(NSInteger)toIndex;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#interface BNRItemStore ()
#property (nonatomic) NSMutableArray *privateItems;
#end
#implementation BNRItemStore
+ (instancetype)sharedStore
{
static BNRItemStore *sharedStore = nil;
// Do I need to create a sharedStore?
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
// If a programmer calls [[BNRItemStore alloc] init], let him
// know the error of his ways
- (instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton"
reason:#"Use +[BNRItemStore sharedStore]"
userInfo:nil];
return nil;
}
// Here is the real (secret) initializer
- (instancetype)initPrivate
{
self = [super init];
if (self) {
_privateItems = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)allItems
{
return [self.privateItems copy];
}
- (BNRItem *)createItem
{
BNRItem *item = [BNRItem randomItem];
[self.privateItems addObject:item];
return item;
}
- (void)removeItem:(BNRItem *)item
{
NSString *key = item.itemKey;
if (key) {
[[BNRItemStore sharedStore] deleteImageForKey:key];
}
[self.privateItems removeObjectIdenticalTo:item];
}
- (void)moveItemAtIndex:(NSInteger)fromIndex
toIndex:(NSInteger)toIndex
{
if (fromIndex == toIndex) {
return;
}
// Get pointer to object being moved so you can re-insert it
BNRItem *item = self.privateItems[fromIndex];
// Remove item from array
[self.privateItems removeObjectAtIndex:fromIndex];
// Insert item in array at new location
[self.privateItems insertObject:item atIndex:toIndex];
}
#end
BNRImageStore.h
#import <Foundation/Foundation.h>
#interface BNRImageStore : NSObject
+ (instancetype)sharedStore;
- (void)setImage:(UIImage *)image forKey:(NSString *)key;
- (UIImage *)imageForKey:(NSString *)key;
- (void)deleteImageForKey:(NSString *)key;
#end
BNRImageStore.m
#import "BNRImageStore.h"
#interface BNRImageStore ()
#property (nonatomic, strong) NSMutableDictionary *dictionary;
#end
#implementation BNRImageStore
+ (instancetype)sharedStore
{
static BNRImageStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[self alloc] initPrivate];
}
return sharedStore;
}
// No one should call init
- (instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton"
reason:#"Use +[BNRImageStore sharedStore]"
userInfo:nil];
return nil;
}
// Secret designated initializer
- (instancetype)initPrivate
{
self = [super init];
if (self) {
_dictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setImage:(UIImage *)image forKey:(NSString *)key
{
self.dictionary[key] = image;
}
- (UIImage *)imageForKey:(NSString *)key
{
return self.dictionary[key];
}
- (void)deleteImageForKey:(NSString *)key
{
if (!key) {
return;
}
[self.dictionary removeObjectForKey:key];
}
#end
You are declaring the method deleteImageForKey in your BNRImageStore class, not in your BNRItemStore.
Check your implementation of removeItem: in BNRItemStore.m
- (void)removeItem:(BNRItem *)item
{
NSString *key = item.itemKey;
if (key) {
[[BNRItemStore sharedStore] deleteImageForKey:key];
}
[self.privateItems removeObjectIdenticalTo:item];
}
I assume you meant to refer to "BNRImageStore" and not BNRItemStore.
Apart from the typo, you should understand that Objective-C objects respond to selectors. Every Objective-C object has an array of selectors that it responds to. When you see the error: "No visible #interface for 'BNRItemStore' declares the selector 'deleteImageForKey;'" you should understand that the compiler does not see the selector you specified as being understood by the class in the error.

Memory leak with objective-c on alloc

When I use Instruments to find memory leaks, a leak is detected on
Horaires *jour;
jour= [[Horaires alloc] init]; // memory leak reported here by Instruments
self.lundi = jour;
[jour release];
and I don't know why there is a leak at this point.
Does anyone can help me? Here's the code.
// HorairesCollection.h
#import <Foundation/Foundation.h>
#import "Horaires.h"
#interface HorairesCollection : NSObject < NSCopying > {
Horaires *lundi;
}
#property (nonatomic, retain) Horaires *lundi;
-init;
-(void)dealloc;
#end
// HorairesCollection.m
#import "HorairesCollection.h"
#implementation HorairesCollection
#synthesize lundi;
-(id)copyWithZone:(NSZone *)zone{
HorairesCollection *another = [[HorairesCollection alloc] init];
another.lundi = [lundi copyWithZone: zone];
[another autorelease];
return another;
}
-init{
self = [super init];
Horaires *jour;
jour= [[Horaires alloc] init]; // memory leak reported here by Instruments
self.lundi = jour;
[jour release];
return self;
}
- (void)dealloc {
[lundi release];
[super dealloc];
}
#end
// Horaires.h
#import <Foundation/Foundation.h>
#interface Horaires : NSObject <NSCopying>{
BOOL ferme;
BOOL h24;
NSString *h1;
}
#property (nonatomic, assign) BOOL ferme;
#property (nonatomic, assign) BOOL h24;
#property (nonatomic, retain) NSString *h1;
-init;
-(id)copyWithZone:(NSZone *)zone;
-(void)dealloc;
#end
// Horaires.m
#import "Horaires.h"
#implementation Horaires
-(BOOL) ferme {
return ferme;
}
-(void)setFerme:(BOOL)bFerme{
ferme = bFerme;
if (ferme) {
self.h1 = #"";
self.h24 = NO;
}
}
-(BOOL) h24 {
return h24;
}
-(void)setH24:(BOOL)bH24{
h24 = bH24;
if (h24) {
self.h1 = #"";
self.ferme = NO;
}
}
-(NSString *) h1 {
return h1;
}
-(void)setH1:(NSString *)horaire{
[horaire retain];
[h1 release];
h1 = horaire;
if (![h1 isEqualToString:#""]) {
self.h24 = NO;
self.ferme = NO;
}
}
-(id)copyWithZone:(NSZone *)zone{
Horaires *another = [[Horaires alloc] init];
another.ferme = self.ferme;
another.h24 = self.h24;
another.h1 = self.h1;
[another autorelease];
return another;
}
-init{
self = [super init];
return self;
}
-(void)dealloc {
[h1 release];
[super dealloc];
}
#end
You've set your property to retain and you alloc and release the variable, so from what I can see the code is okay and Instruments has given you a false warning.
I think your copyWithZone: might have a leak, though. [lundi copyWithZone:] will retain a copy of lundi but you never release it. So you need an extra release, something like this:
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires alloc] init];
Horaires* makeCopy = [lundi copyWithZone: zone];
another.lundi = makeCopy;
[makeCopy release];
return another;
}
This is because copy and alloc both return retained object instances and you need to manually release them when you're finished with them. You did that correctly for your alloc'd objects but not the copy.
That init method looks ok, although it should be implemented (and typed) as
-(id)init
{
if (self = [super init])
{
...
}
return self;
}
or a similar pattern.
Your copyWithZone implementations are wrong, they need to return a retained object, so do not autorelease the returned value. But you need to release your copy of lundi, because you are using the retaining setter.
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires alloc] init];
Horaires *lundiCopy = [lundi copyWithZone:zone];
another.lundi = lundiCopy;
[lundiCopy release];
return another;
}
I don't know why you return an instance of DefibHoraires here, shouldn't it be a HorairesCollection?
Maybe the wrong copyWithZone: method is responsible for the reported leak (it's a leak anyway).
One further note: It's a good defensive rule to use (copy) for NSString properties instead of (retain) to remove side effects when passing NSMutableString instead.
I don't have an answer but I do have some general comments:
In copyWithZone: you should use allocWithZone: (passing the same zone as a parameter) to allocate the object you are going to return.
copyWithZone: should return a retained object. Don't autorelease it.
You are not supposed to use properties in init. Your init should look something like:
-init
{
self = [super init];
if (self != nil)
{
lundi = [[Horaires alloc] init]; // assign the ivar directly
}
return self;
}
In your copyWithZone: for HorairesCollection you have a leak. It should look like:
-(id)copyWithZone:(NSZone *)zone{
DefibHoraires *another = [[DefibHoraires allocWithZone: zone] init];
another.lundi = [[lundi copyWithZone: zone] autorelease];
return another;
}

Leak on iPad that I don't understand

I've got a leak in my application and I do not know why. Maybe I've got all memory managment thing wrong. In my code I've got UIViewController object which have ivar TelephoneValidator *validator
TelephoneValidator is TelephoneValidator : NSObject
So in my initialization function of UIViewController object (initWithFieldData) I've got:
-(id) initWithFieldData: (NSMutableDictionary*) fieldData
{
...
validatorOptions = [fieldData objectForKey:#"fieldValidator"];
...
}
Now in my viewDidLoad I've got:
- (void)viewDidLoad {
...
if (![validatorOptions respondsToSelector:#selector(isEqualToString:)]) {
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
}
else {
validator = nil;
}
...
}
Basicly if my validatorOptions isn't NSString the validator ivar became TelephoneValidator instance.
In my dealloc:
- (void)dealloc {
if(validator != nil)
{
[validator release];
validator = nil;
}
...
[super dealloc];
}
I've checked a couple of times if dealloc works, and it is. After calling dealloc the validator is released (calling any method on validator after [validator release] gets me exception).
And yet in Instruments it is telling me that TelephoneValidator is leaked. And after double clicking in Instruments the line of code that is highlited is:
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
What am I doing wrong?
UPDATE:
Here is my header information of UIViewController:
#interface GenericViewController : UIViewController <UITextFieldDelegate>{
UIImage *backgroundImage;
NSString *step; // na ktorym kroku jestesmy
id <GenericControllerDelegate> delegate; //delegata z ktorej bedziemy pobierali dane
UITextField *textField;
NSString *fieldName; //nazwa pola (potrzebujemy zeby zapisac do modelu odpowiedni tekst
UILabel *textLabel;
UILabel *stepsLabel;
UILabel *prefixTextLabel;
NSString *fieldPlaceholder;
NSString *textLabelText;
NSString *textLabelTextPl; //w jezyku polskim
NSString *prefixTextLabelText; //w jezyku eng
NSString *prefixTextLabelTextPl; //w jezyku polskim prefix
NSString *fieldRequired;
NSString *keyboardType;
NSString *capitalizeType;
UIButton *button; //forward button
UIButton *button2; //backward button
//to bedzie do przerobienia bo bedziemy mieli tablicje walidatorow a nie jeden walidator
NSString *validatorType;
//maksymalna dlugosc pola
int maxLengthOfTextField;
NSArray* validatorOptions;
TelephoneValidator *validator;
//patientModel
PatientData *patientModel;
}
TelephoneValidator header:
#import <Foundation/Foundation.h>
#import "MAOTranslate.h"
#interface TelephoneValidator : NSObject {
//opcje walidacyjne
NSString *phonePrefix;
NSString *phonePostfix;
int phoneLength;
NSString *message;
NSString *messagePl;
UIAlertView *alertView;
}
-(id) initWithOptions:(NSArray *) optionsArray;
-(void) displayMessage;
-(BOOL) validate: (NSString *) phoneNumber;
#end
TelephoneValidator class:
#import "TelephoneValidator.h"
#implementation TelephoneValidator
//#synthesize phoneNumber;
-(id) initWithOptions:(NSArray *) optionsArray;
{
if(self = [[TelephoneValidator alloc] init])
{
phonePrefix = [optionsArray objectAtIndex:0];
phonePostfix = [optionsArray objectAtIndex:1];
phoneLength = [[optionsArray objectAtIndex:2] intValue];
message = [optionsArray objectAtIndex:3];
messagePl = [optionsArray objectAtIndex:4];
}
else {
self = nil;
}
return self;
}
//wyswietlamy wiadomosc
-(void) displayMessage
{
NSString *displayMsg;
if ([[MAOTranslate getLanguage] isEqualToString:#"pl"]) {
displayMsg = messagePl;
}
else {
displayMsg = message;
}
alertView = [[UIAlertView alloc] initWithTitle:#"Alert" message:displayMsg delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alertView show];
}
-(BOOL) validate: (NSString *) phoneNumber
{
//dlugosc
if ([phoneNumber length] != phoneLength) {
NSLog(#"zla dlugosc");
return NO;
}
NSLog(#"tutaj");
//sprawdzamy prefix
if ([phonePrefix length]!= 0) {
NSLog(#"w srodku ifa");
if ([phoneNumber compare:phonePrefix options:NSLiteralSearch range:NSMakeRange(0, [phonePrefix length])] != 0) {
NSLog(#"zly prefix");
[self displayMessage];
return NO;
}
}
//sprawdzamy postfix
if([phonePostfix length] != 0)
{
if ([phoneNumber compare:phonePostfix options:NSLiteralSearch range:NSMakeRange([phoneNumber length]-[phonePostfix length], [phonePostfix length])] != 0) {
NSLog(#"zly postfix");
[self displayMessage];
return NO;
}
}
//sprawdzamy czy string jest numeryczny
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:phoneNumber];
if (![alphaNums isSupersetOfSet:inStringSet])
{
NSLog(#"zly format ");
[self displayMessage];
return NO;
}
return YES; //zwalidowany poprawnie
}
-(void) dealloc
{
[alertView release];
alertView = nil;
[super dealloc];
}
You need to call [super dealloc] at the end of the dealloc method.
See These both lines
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
and inside initWithOptions
if(self = [[TelephoneValidator alloc] init])
You are allocing twice the validator, so there is a leak.
Could it be that instruments is pointing to validatorOptions as the source of the leak? Is it a retained property being released at dealloc or not? I can't say for sure, the code you posted is not enough to arrive to a conclusion.
Also, as willcodejavaforfood says, you must always call [super dealloc]; at the end of your dealloc method. No code must come after it.
Edit:
I'm back. But Bruno Domingues got it right already, you are allocating twice, in which case, the first one leaks. You should change your -initWithOptions: code to:
-(id) initWithOptions:(NSArray *) optionsArray;
{
if((self = [super init])){
// ... rest of code is fine
}
return self;
}