Why does Xcode skip for loop code? - ios

Just want to ask if this method initWithNibName ends, will the logInIDArray and passwordArray property become nil again?
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
//sharedLogInDataBase returns singleton
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
BNRLogInDataBase *logInDatabase = [BNRLogInDataBase sharedLogInDataBase];
logInDatabase.logInIDArray = [[NSMutableArray alloc]init];
logInDatabase.passwordArray = [[NSMutableArray alloc]init];
}
return self;
}
here's the singleton method
+(instancetype)sharedLogInDataBase
{
static BNRLogInDataBase * database = nil;
if (!nil) {
database = [[BNRLogInDataBase alloc]initPrivate];
}
return database;
}
-(instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton" reason:#"use sharedLogInDataBase" userInfo:nil];
}
-(instancetype)initPrivate
{
self = [super init];
return self;
}

Your method should be:
+ (instancetype)sharedLogInDataBase
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Currently your if (!nil) is not doing what you expect it to...
Then, your init method should call your initPrivate method.

They cannot become nil because you instantiated them. Though they will be empty.

It will depends on:
How you implemented your BNRLogInDataBase singleton, if you use a strong reference to keep the singleton instance logInDatabase will stay, if not it will be deallocated
How you declared logInIDArray and passwordArray properties, if strong they will remain as long as logInDatabase exists, if weak they will become nil
if (!nil) {
database = [[BNRLogInDataBase alloc]initPrivate];
}
Check your test, nil is always false, so !nil is always true, each time you call your singleton you get a different object !

Related

Why block can't capture self?

I used a data object to store an array data and when the data load completes, I have a block callback. But the problem is that there are different instances in the two methods:
#implementation DWHomeData
- (instancetype)initWithDataLoadCompletion:(void (^)(BOOL))completion
DWHomeData *data = [DWHomeData new];
data.dwStatus = [#[] mutableCopy];
_completion = [completion copy];
[self loadStatusData];
return data;//<DWHomeData: 0x7fb481546860>
}
- (void)loadStatusData {
DWHomeParam *param = [DWHomeParam new];
[DWHomeTool fetchHomeStatusWithParam:param success:^(NSArray *statusArr) {
self.dwStatus = statusArr;//self address:<DWHomeData: 0x7fb481548b00>
_completion(YES);
} failure:^(NSError *error) {
}];
}
#end
My callback is:
- (void)viewDidLoad {
[super viewDidLoad];
_homeData = [[DWHomeData alloc] initWithDataLoadCompletion:^(BOOL success) {
[self.tableView reloadData];
}];//_homeData address:<DWHomeData: 0x7fb481546860>
}
It's because you are allocing it twice. The method new is just a wrapper for an alloc and an init.
So when you call [[DWHomeData alloc] initWith... you allocated memory for the first instance of DWHomeData.
Then, inside the initWith... method you are calling new which allocated memory for the second instance of DWHomeData and you return that second instance, but you call loadStatusData on the first instance.
The easiest solution would be to replace that new call with the standard:
self = [super init]; // no alloc
if (self) {
// initialize properties and call methods
}
return self;
Or you can do how I like to do all the time:
+ (instancetype)dataWithCompletion:(void (^)(BOOL))completion { // static method
DWHomeData *data = [DWHomeData new]; // alloc needed
if (data) {
[data loadStatusData];
}
return data;
}
and then call it without allocating:
_homeData = [DWHomeData dataWithCompletion:^(BOOL success) {
[self.tableView reloadData];
}];
so the alloc is wrapped inside the static init method and there is no need to call it outside.

Method not getting called in iOS

I have the following snippet and a call to the method is not working!
#interface myVM(){
NSArray *results;
}
#property (nonatomic, strong) MyModel *model;
#end
#implementation myVM
- (instancetype)initWithItems{
self = [super init];
if (!self) return nil;
**[self.model loadInfo];**
_DeviceNameArray = self.model.DeviceNames;
}
What is the reason for the method being not called?
You have to allocate and initialize it first:
- (instancetype)initWithItems{
self = [super init];
if (!self) return nil;
self.model = [MyModel new]; // like this
[self.model loadInfo];
_DeviceNameArray = self.model.DeviceNames;
return self;
}
self.model is not initialized. If you debug it, you will see it is nil.
By the time you are calling [self.model loadInfo];, the model property has not been set yet and is nil. You probably want something like:
- (instancetype)initWithModel:(MyModel *)aModel {
self = [super init];
if (!self) return nil;
self.model = aModel;
[self.model loadInfo];
_DeviceNameArray = self.model.DeviceNames;
return self;
}
You should structure your custom init methods like this for better readability.
- (instancetype)initWithItems
{
self = [super init];
if (self) {
[self.model loadInfo];
_DeviceNameArray = self.model.DeviceNames;
}
return self;
}
The problem is that self.model has not been initialised anywhere. It is just a property that contains no information - it is nil. You need to assign something to it somewhere.
E.g., pass a model object as parameter like so, initWithItem:(MyModel *)model, then assign it to self.model.

Trying to temporarily store objects in an NSMutableArray in a Singleton class for later use in iOS

I have a Singleton class that has two methods:
- (void)saveString:(NSString *)stringObject {
[[[Singleton sharedInstance] stringArray] addObject:stringObject];
}
- (NSArray *)getArrayContents {
return [[Singelton sharedInstance] stringArray];
}
Here is the implementation code of my Singleton class:
static Singleton *sharedSingleton = nil;
+ (Singleton *) sharedInstance {
if (sharedSingleton == nil) {
sharedSingleton = [[super alloc] init];
}
return sharedSingleton;
}
I have two View Controllers (vcA, and vcB) in my application. What I am trying to do is temporarily store the data from vcA, so that the data inside stringArray will be accessible later to vcB.
Here is the code that vcA uses to store the data:
[[Singleton sharedInstance] saveString:stringName];
Later in the lifecycle of the application, vcB calls the Singleton class to retrieve the values from the NSMutableArray:
NSArray *newArray = [[Singleton sharedInstance] getArrayContents];
for (NSString *test in newArray) {
NSLog(#"Here are the contents of the array %#", test);
}
Unfortunately, when I make the call in vcB to print the contents of the Array, there is no output because the array is empty, despite the fact that values are added to the array. What is it I'm doing wrong?
Try this,
to create Singleton
+(Singleton *)sharedSingleton {
static dispatch_once_t once;
static Singleton *sharedSingleton;
dispatch_once(&once, ^{
sharedSingleton = [[self alloc] init];
});
return sharedSingleton;
}
and the init method of singleton class
- (id)init
{
self = [super init];
if (self) {
//#property stringArray
self.stringArray = [[NSMutableArray alloc] init];
}
return self;
}
Other methods of Singleton
- (void)saveString:(NSString *)stringObject {
[self.stringArray addObject:stringObject];
}
- (NSArray *)getArrayContents {
return self.stringArray;
}
I had this problem. My code in the singleton looked like this:
+ (ReportDataList*)sharedDataArray
{
static dispatch_once_t pred;
static ReportDataList *shared = nil;
dispatch_once(&pred, ^{
shared = [[ReportDataList alloc] init];
self.rDetailsArray = [[NSMutableArray alloc] init];
});
return shared;
}
I had incorrectly initialised the array, so it was emptying it when I created a reference to the singleton later in my code. I removed the array initialisation, which is done in the -(id)init method and it worked fine. So, my code then looked like this:
+ (ReportDataList*)sharedDataArray
{
static dispatch_once_t pred;
static ReportDataList *shared = nil;
dispatch_once(&pred, ^{
shared = [[ReportDataList alloc] init];
});
return shared;
}
- (id)init
{
self = [super init];
if (self) {
self.rDetailsArray = [[NSMutableArray alloc] init];
[self initWithDummyValues];
}else{
NSLog(#"problem initialising array list");
}
return self;
}
First off, these two methods should probably use self, not sharedInstance:
- (void)saveString:(NSString *)stringObject {
[[self stringArray] addObject:stringObject];
}
- (NSArray *)getArrayContents {
return [self stringArray];
}
Second, there’s no point in having a getArrayContents method when you already have stringArray, and get as a prefix is usually reserved for methods that take a parameter to be copied into, anyhow.
Third, I don’t see you initializing stringArray anywhere, so unless there’s code missing, it’s nil and it’s staying nil. Maybe try:
+ (Singleton *) sharedInstance {
if (!sharedSingleton) {
sharedSingleton = [[self alloc] init];
sharedSingleton.stringArray = [NSMutableArray new];
}
return sharedSingleton;
}
Assuming stringArray is declared something like:
#property (readwrite, strong) NSMutableArray *stringArray;

Issues with singleton

I have created a single ton like this for ARC,
+ (MyClass *)sharedInstance {
static MyClass *sharedSpeaker = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSpeaker = [[self alloc] init];
});
return sharedSpeaker;
}
- (id)init {
if (self = [super init]) {
}
return self;
}
But here I am creating instances like this:
id speaker3 = [[MyClass alloc] init];
id speaker = [MyClass sharedInstance];
id speaker2 = [[MyClass alloc] init];
NSLog(#"Speaker 1= %# \n speaker 2 = %#\n Speaker3 = %#",speaker,speaker2,speaker3);`
I got output as:
Speaker 1= <MyClass : 0xa45f5e0>
speaker 2 = <MyClass : 0xa461740>
Speaker3 = <MyClass : 0xa4529e0>
This is looking like a desired behaviour. How to stop this when I am giving singleton in library to user. I need to block him from creating new instance. Do I need to make static global if I make it global he cant create the global variable of the same name there will be conflict right. So any memebers can give solution on this?
For example using an assert in the init method.
- (id)init {
static int maxInstances = 1;
assert(maxInstances > 0);
maxInstances--;
...
}
Because you are creating new instances of your singleton class using alloc, init.
You will get the singleton instance using the sharedInstance class method. Like:
id speaker = [MyClass sharedInstance];
If you don't want to create the instances with alloc or init. Override those methods.
You can write static MyClass *sharedSpeaker = nil; as a static global variable and remove it from the sharedInstance method.
in .h file
#import <Foundation/Foundation.h>
#interface Singleton : NSObject
{
///......
}
+ (Singleton *)sharedSingleton;
in .m file
#import "Singleton.h"
#implementation Singleton
static Singleton *singletonObj = NULL;
+ (Singleton *)sharedSingleton
{
#synchronized(self)
{
if (singletonObj == NULL)
singletonObj = [[self alloc] init];
}
return(singletonObj);
}
and use this in another file
#import "Singleton.h"
//.....
Singleton *sinObj = [Singleton sharedSingleton]; // not alloc and init. use direct
create instance like this it will always return you singlton
static testSinglton *myinstance = nil;
+ (testSinglton *) sharedInstance {
if (!myinstance) {
myinstance = [[testSinglton alloc] init];
}
return myinstance;
}
- (id) init {
if (myinstance) {
return myinstance;
}
if (self = [super init]) {
//new object now will be created...
myinstance = self;
}
return self;
}
NSLog(#"%#",[[testSinglton alloc] init]);
NSLog(#"%#",[testSinglton sharedInstance]);
NSLog(#"%#",[[testSinglton alloc] init]);

Objective C - sample Singleton implementation

*I definitely need a break... cause was simple - array was not allocated... Thanks for help. Because of that embarrassing mistake, I flagged my post in order to delete it. I do not find it useful for Users ;) *
I have just tried to create a singleton class in iOS, but I probably I am making a mistake. Code (no ARC is a requirement):
#import "PeopleDatabase.h"
#import "Person.h"
#import <Foundation/Foundation.h>
#interface PeopleDatabase : NSObject{objetive
NSMutableArray* _arrayOfPeople;
}
+(PeopleDatabase *) getInstance;
#property (nonatomic, retain) NSMutableArray* arrayOfPeople;
#end
--
#implementation PeopleDatabase
#synthesize arrayOfPeople = _arrayOfPeople;
static PeopleDatabase* instance = nil;
-(id)init{
if(self = [super init]) {
Person* person = [[[Person alloc] initWithName:#"John" sname:#"Derovsky" descr:#"Some kind of description" iconName:#"johnphoto.png" title:Prof] retain];
[_arrayOfPeople addObject:person];
NSLog(#"array count = %d", [_arrayOfPeople count]); // <== array count = 0
[person release];
}
return self;
}
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return(instance);
}
-(void)dealloc {
[instance release];
[super dealloc];
}
#end
When invoking getInstance like here:
PeopleDatabase *database = [PeopleDatabase getInstance];
NSLog(#"Adress 2: %p", database);
Address 2 value the same value as in getInstance.
The standard way of creating a singleton is like...
Singleton.h
#interface MySingleton : NSObject
+ (MySingleton*)sharedInstance;
#end
Singleton.m
#import "MySingleton.h"
#implementation MySingleton
#pragma mark - singleton method
+ (MySingleton*)sharedInstance
{
static dispatch_once_t predicate = 0;
__strong static id sharedObject = nil;
//static id sharedObject = nil; //if you're not using ARC
dispatch_once(&predicate, ^{
sharedObject = [[self alloc] init];
//sharedObject = [[[self alloc] init] retain]; // if you're not using ARC
});
return sharedObject;
}
#end
Check this apple doc on how to create singleton instance:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
You appear to be missing your braces for that if statement. As written, the only thing you do different when instance == nil is emit a log message.
After web reading and personal practicing, my current singleton implementation is:
#interface MySingleton
#property myProperty;
+(instancetype) sharedInstance;
#end
#implementation MySingleton
+ (instancetype) sharedInstance
{
static dispatch_once_t pred= 0;
__strong static MySingleton *singletonObj = nil;
dispatch_once (&pred, ^{
singletonObj = [[super allocWithZone:NULL]init];
singletonObj.myProperty = initialize ;
});
return singletonObj;
}
+(id) allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
-(id)copyWithZone:(NSZone *)zone
{
return self;
}
this is a thread safe implementation and avoids the risk to create new objects by calling "alloc init" on your class. Attributes initialization has to occur inside the block, not inside "init" override for similar reasons.
This is an error that can be avoided by some disziplined convention which is to always use curly brackets followed by if and else.
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return(instance);
}
If instance is nil then the very next statement and only that is executed. And that is the nslog and not the allocation. Then instance is allocated anyway, regardless wether it was used before or not. This will provide you with a new singleton on each call. BTW that causes a leak.
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil) {
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
}
return(instance);
}
But this error came in while debugging. It may confuse you but does not solve your original problem. Please add an alloc and init and retain for _arrayOfPeople as well.
-(id)init{
if(self = [super init]) {
Person* person = [[[Person alloc] initWithName:#"John" sname:#"Derovsky" descr:#"Some kind of description" iconName:#"johnphoto.png" title:Prof] retain];
_arrayOfPeople = [[[NSMutableArray alloc] init] retain]; //dont forget the release
[_arrayOfPeople addObject:person];
NSLog(#"array count = %d", [_arrayOfPeople count]); // <== array count = 1 !!!
[person release];
}
return self;
}
In your code _arrayOfPeople is nil and addObject is sent to nil which does not cause an abort but does not do anything either. Then count is sent to nil wich returns 0/nil.
in this function +(PeopleDatabase *)getInstance i think you need to place curly Braces correctly : like this
+(PeopleDatabase *)getInstance {
#synchronized(self)
{
if (instance == nil)
{
NSLog(#"initializing");
instance = [[[self alloc] init] retain];
NSLog(#"Address: %p", instance);
}
return instance ;
}
}

Resources