Unable to add object to nsmutable array in singleton - ios

The same code works on iOS 5 but not in iOS 6. That is the count shows as being 0. Any ideas?
It should say atleast 1 as the count since I have verified house.png to be a valid image.
Here is my code:
MyManager * myManager = [MyManager sharedInstance];
NSString *pathOfImageFile = [[NSBundle mainBundle] pathForResource:#"house" ofType:#"png"];
UIImage *myImage = [UIImage imageWithContentsOfFile:pathOfImageFile];
UIImageView * tempImageView = [[UIImageView alloc] initWithImage:myImage];
[myManager.assets addObject:tempImageView];
NSLog(#"image count: %d", [myManager.assets count]);
Here is my singleton:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyManager : NSObject
{
MyManager *_sharedObject;
NSMutableArray * assets;
}
//Property Listing
#property(nonatomic,copy) NSString * postTitle;
#property(nonatomic,copy) NSString * postText;
#property(nonatomic,copy) NSString * postLink;
#property(nonatomic,copy) NSString * postCategory;
//assets
#property (nonatomic, strong) NSMutableArray * assets;
+ (id)sharedInstance;
- (void)reset;
#end
#import "MyManager.h"
#implementation MyManager
//Property Listing
#synthesize postTitle=_postTitle;
#synthesize postText=_postText;
#synthesize postLink=_postLink;
#synthesize postCategory=_postCategory;
#synthesize assets=_assets;
- (id)init
{
self = [super init];
if ( self )
{
assets = [[NSMutableArray alloc] init];
NSLog(#"Singleton Initialized...");
}
return self;
}
+ (id)sharedInstance
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
- (void)reset
{
self.postTitle =#"";
self.postText=#"";
self.postLink=#"";
self.postCategory=#"";
[self.assets removeAllObjects];
}
#end

You have extra ivars related to your assets property.
You define a property named assets. You then (needlessly) synthesize the property specifying that the generated ivar should be named _assets.
You also (needlessly) declare an explicit ivar named assets.
In your init method you assign the array to the assets ivar. In your reset method you clear the assets property (using the _assets ivar).
Get rid of the explicit assets ivar. Get rid of the #synthesize statement. This will leave you with an auto generated ivar of _assets.
Update your code to use either the property or the _assets ivar.

Try:
_assets = [[NSMutableArray alloc] init];
And you are defining sharedObject in your interface as a property: MyManager *_sharedObject;
You don't want that if you'll always grab your instance via [MyManager sharedInstance]; which is holding the initialized instance in that local static var.

Related

How to use shared preference in xcode using objective-c? [duplicate]

This question already has answers here:
How to save NSMutablearray in NSUserDefaults
(9 answers)
Closed 5 years ago.
In one view controller, I store some array value and I will get that value from another view controller.
How to save array value in shared manager and how to retrieve that array value from another view controller? How to use shared preference in Xcode? Is that possible? Please help me with the example.Thank you.
my code is
(id)sharedManager {
static AssistantView *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
and i put the value
[[AssistantView sharedManager]results]; // where results is array
Use NSUserDefaults
Set
[[NSUserDefaults standardUserDefaults] setObject:#"Your Object" forKey:#"NameOfPreference"];
[[NSUserDefaults standardUserDefaults] synchronize];
Get
NSString *savedObject = [[NSUserDefaults standardUserDefaults]
stringForKey:#"NameOfPreference"];
// its Your Object
Alternative using AppDelegate
1 Define Macro
#define APPDELEGATE ((AppDelegate *)[[UIApplication sharedApplication] delegate])
2 add property for object in Appdelegate
#property (nonatomic) NSArray *arrObjects;
3 set object to property .
APPDELEGATE.arrObjects = #[#"",#""];
4 Get value
NSArray *globalObjects = APPDELEGATE.arrObjects
you should use a singleton class like this
#import <foundation/Foundation.h>
#interface MySingleton : NSObject {
}
#property (nonatomic, retain) NSArray *mySharedArray;
+(id)sharedMySingleton;
#end
and in .m file
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(id)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
_sharedMySingleton = [[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
and call it in any viewController like
[[MySingleton sharedMySingleton] mySharedArray];
1) Create a File with NSObject as subclass (i.e SharedClass)
SharedClass.m
#implementation SharedClass
+ (instancetype)sharedManager {
static SharedClass *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] init];
});
return sharedManager;
}
- (instancetype)init {
if (self = [super init]) {
// alloc or set object here
return self;
}
SharedClass.h
#import <Foundation/Foundation.h>
#interface SharedClass : NSObject
+ (instancetype)sharedManager;
// your array
#end
2) To access array
[[SharedClass sharedManager]array];
3) To set array
[[SharedClass sharedManager]setArray];

Objective-C Defining a Global Array for use by several ViewControllers

I've been trying to implement a global NSMutableArray from what I think to be a singleton class that I've implemented.
I can enter ViewController # 2, add and remove objects to the array.
However, when I leave ViewController #2 and come back, the data does not persist, and I have an array with 0 objects.
What do you think I'm doing wrong?
.h
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
.m
#import "GlobalArray.h"
#implementation GlobalArray
static GlobalArray* sharedGlobalArray;
NSMutableArray* globalArray;
+(void)initialize{
static BOOL initalized = NO;
if(!initalized){
initalized = YES;
sharedGlobalArray = [[GlobalArray alloc] init];
}
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
View Controller #2
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
//Various add and remove code
Thank you for your input.
Following is best approach to share data Globally at Application level. Singleton Class is a key. Singleton is only initialised once, rest of times shared data is returned.
#interface Singleton : NSObject
#property (nonatomic, retain) NSMutableArray * globalArray;
+(Singleton*)singleton;
#end
#implementation Singleton
#synthesize globalArray;
+(Singleton *)singleton {
static dispatch_once_t pred;
static Singleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
shared.globalArray = [[NSMutableArray alloc]init];
});
return shared;
}
#end
Following is the way to access/use shared data.
NSMutableArray * sharedData = [Singleton singleton].globalArray;
You create separate instance of GlobalArray in your ViewController#2 with this code:
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
Instead, you should create accessor method to return your shared instance, something like this:
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
+(GlobalArray*)sharedInstance;
with implementation:
// GlobalArray.m
// ... your existing code
// accessor method
+(GlobalArray*)sharedInstance
{
return sharedGlobalArray;
}
and then call it from your ViewController#2:
GlobalArray* myGlobalArray = [GlobalArray sharedInstance];
However, using global variables to transfer data between view controllers is bad practice; I suggest you to use more safe methods, create a delegate, for example.
To create a shared global array, if that's really what you want, just put this in the header file:
extern NSMutableArray *myGlobalArray;
and this in your main source file:
NSMutableArray *myGlobalArray;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
myGlobalArray = [NSMutableArray new];
}
Use this code for set and get the array views, for adding and removing do it separate in controller itself.
// GlobalArray.h
#interface GlobalArray : NSObject
#property (nonatomic, strong) NSMutableArray* globalArray;
+ (id)sharedManager;
-(NSMutableArray *) getGlobalArray;
-(void) setGlobalArray:(NSMutableArray *)array;
#end
/*-----------------------------------------*/
#import "GlobalArray.h"
#implementation GlobalArray
+ (id)sharedManager {
static GlobalArray *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
-(NSMutableArray *) getGlobalArray{
return self.globalArray;
}
-(void) setGlobalArray:(NSMutableArray *)array{
_globalArray = globalArray;
}
#end
-------------------------
//get array
NSArray * array = [[GlobalArray sharedManager] getGlobalArray];
//set array
[[GlobalArray sharedManager] setGlobalArray:array]
-------------------------

How to retrieve an image from an asset field in CloudKit using objective-c

I have a record type in CloudKit. It stores one string field and one asset field. Using the dashboard I uploaded an image to the asset field.
I can retrieve the string field. I now need to retrieve the contents of the asset field and store it to an image using objective-c. Can anyone help?
I am trying to display the record type in a table view. I have a class called TJKCategoriesViewController that inherits from UIViewController.
I have this code in my viewDidLoad method for the TJKCategoriesViewController class:
// get all categories
_jokeCategories = [[NSMutableArray alloc] init];
CKDatabase *jokePublicDatabase = [[CKContainer containerWithIdentifier:JOKE_CONTAINER] publicCloudDatabase];
NSPredicate *predicateCategory = [NSPredicate predicateWithFormat:#"CategoryName != %#", CATEGORY_TO_REMOVE_OTHER];
CKQuery *queryCategory = [[CKQuery alloc] initWithRecordType:CATEGORY_RECORD_TYPE predicate:predicateCategory];
NSSortDescriptor *sortCategory = [[NSSortDescriptor alloc] initWithKey:CATEGORY_FIELD_NAME ascending:YES];
queryCategory.sortDescriptors = [NSArray arrayWithObjects:sortCategory, nil];
[jokePublicDatabase performQuery:queryCategory inZoneWithID:nil completionHandler:^(NSArray<CKRecord*>* results, NSError * error)
{
if (!error)
{
// add all categories to array
for (CKRecord* jokeCategory in results)
{
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory valueForKey:#"CategoryImage"]];
[_jokeCategories addObject:categories];
}
NSLog(#"Categories = %#",_jokeCategories);
// setup table
[self setupTableContents];
}
else
{
// display alert message and pop the view controller from the stack
GHSAlerts *alert = [[GHSAlerts alloc] initWithViewController:self];
errorActionBlock errorBlock = ^void(UIAlertAction *action) {[self closeCategories:self];};
[alert displayErrorMessage:#"Oops!" errorMessage:#"The joke categories failed to load. This screen will close. Just try again!" errorAction:errorBlock];
}
}];
This is the method "setupTableContents"
// setup the array that will hold the table's contents
-(void)setupTableContents
{
// store to property and reload the table contents
dispatch_async(dispatch_get_main_queue(), ^{
[self.categoriesTableView reloadData];
});
}
TJKCategories is a class that stores the two fields in the record type. This is the TJKCategories.h file:
#import <UIKit/UIKit.h>
#interface TJKCategories : NSObject
#pragma Properties
#property (nonatomic, copy) UIImage *categoryImage;
#property (nonatomic, copy) NSString *categoryName;
#pragma Initializers
+(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(UIImage *)categoryImage;
-(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(UIImage *)categoryImage;
#end
This is the TJKCategories.m file:
// designated initializer
-(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(UIImage *)categoryImage
{
self = [super init];
if (self)
{
self.categoryImage = categoryImage;
self.categoryName = categoryName;
}
return self;
}
// class level initializer
+(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(UIImage *)categoryImage
{
TJKCategories *category = [[self alloc]initWithCategory:categoryName categoryImage:categoryImage];
return category;
}
// override default initializer
-(instancetype)init
{
return [self initWithCategory:#"" categoryImage:nil];
}
In the viewDidLoad method I am using: [jokePublicDatabase performQuery:queryCategory inZoneWithID:nil completionHandler:^(NSArray* results, NSError * error)
To retrieve the results of the record type. I am then looping through the results array, I can retrieve the string "CATEGORY_FOR_NAME" (which is a constant for "CategoryName", but when I try and retrieve the field for the image "CategoryImage" I get and "unrecognized selector sent to instance" error.
If you need to know what the names behind the constants are here is my contacts file:
// declare constants
extern NSString *const DEFAULT_CATEGORY;
extern NSString *const JOKE_CONTAINER;
extern NSString *const CATEGORY_RECORD_TYPE;
extern NSString *const CATEGORY_FIELD_NAME;
extern NSString *const CATEGORY_TO_REMOVE_OTHER;
extern NSString *const CATEGORY_TO_REMOVE_RANDOM;
extern NSString *const JOKE_RECORD_TYPE;
extern NSString *const JOKE_DESCR;
extern NSString *const JOKE_SUBMITTED_BY;
extern NSString *const JOKE_TITLE;
// assign values to constants
NSString *const DEFAULT_CATEGORY = #"None";
NSString *const JOKE_CONTAINER = #"iCloud.com.glennseplowitz.Jokes";
NSString *const CATEGORY_RECORD_TYPE = #"Categories";
NSString *const CATEGORY_FIELD_NAME = #"CategoryName";
NSString *const CATEGORY_TO_REMOVE_OTHER = #"Other";
NSString *const CATEGORY_TO_REMOVE_RANDOM = #"Random";
NSString *const JOKE_RECORD_TYPE = #"Jokes";
NSString *const JOKE_DESCR = #"jokeDescr";
NSString *const JOKE_SUBMITTED_BY = #"jokeSubmittedBy";
NSString *const JOKE_TITLE = #"jokeTitle";
So what I am trying to do is retrieve the asset type "CategoryImage" from the record type and store it to a UIImage. But like I said it gives me the error "unrecognized selector sent to instance" because I believe it cannot convert an asset field to a UIImage field directly.
Thanks,
Glenn
Figured it out! I changed my TJKCategories class to accept a CKAsset instead of a UIImage. I then converted the CKAsset to a UIImage.
Here is the TJKCategories.h file:
#import <UIKit/UIKit.h>
#import <CloudKit/CloudKit.h>
#interface TJKCategories : NSObject
#pragma Properties
#property (nonatomic, copy) UIImage *categoryImage;
#property (nonatomic, copy) NSString *categoryName;
#pragma Initializers
+(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(CKAsset *)categoryImageAsset;
-(instancetype)initWithCategory:(NSString *)categoryName
categoryImage:(CKAsset *)categoryImageAsset;
#end
Here is the TJKCategories.m file:
#import "TJKCategories.h"
#interface TJKCategories()
#pragma Properities
#property (nonatomic, strong) CKAsset *categoryImageAsset;
#end
#implementation TJKCategories
#pragma initializers
// designated initializer
-(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(CKAsset *)categoryImageAsset
{
self = [super init];
if (self)
{
self.categoryImageAsset = categoryImageAsset;
self.categoryName = categoryName;
UIImage *image = [[UIImage alloc] initWithContentsOfFile:self.categoryImageAsset.fileURL.path];
self.categoryImage = image;
}
return self;
}
// class level initializer
+(instancetype)initWithCategory:(NSString *)categoryName categoryImage:(CKAsset *)categoryImageAsset
{
TJKCategories *category = [[self alloc]initWithCategory:categoryName categoryImage:categoryImageAsset];
return category;
}
// override default initializer
-(instancetype)init
{
return [self initWithCategory:#"" categoryImage:nil];
}
I also changed the line:
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory **objectForKey**:#"CategoryImage"]];
to
TJKCategories *categories = [TJKCategories initWithCategory:[jokeCategory valueForKey:CATEGORY_FIELD_NAME] categoryImage:[jokeCategory **valueForKey**:#"CategoryImage"]];
Note that CategoryImage is now using valueForKey and not objectForKey.

Can't add object to NSMutableArray in singleton

I made a singleton and i'm trying to add objects to self.timelineArray but i can't. When i do this i have 9 objects:
NSNumber* nmb = [[NSNumber alloc] initWithInt:1];
[self.dataManager.timelineArray addObject:nmb];
After i insert the nmb object, i still have 9 objects.
Here's my singleton header (only important bits):
#interface DataManager : NSObject
#property (nonatomic, strong) NSMutableArray* timelineArray;
Here's my singleton implementation (only important bits):
#import "DataManager.h"
static DataManager* sharedInstance = nil;
#implementation DataManager
+ (DataManager *) sharedInstance{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
- (id)init {
if (self = [super init])
{
self.timelineArray = [[NSMutableArray alloc] init];
}
return self;
}
This is just simple coding and i can't seem to figure out why it does not work.
Trying to modify immutable array(NSArray) will lead to this.
Replace
[responseObject objectForKey:#"timeline"] with [[NSMutableArray alloc] initWithArray:[responseObject objectForKey:#"timeline"]
This was based on the comments of the question.
i'll suggest you to add like following
NSNumber* nmb = [[NSNumber alloc] initWithInt:1];
[[DataManager sharedInstance]timelineArray addObject:nmb];
this will always add into the singleton not the instance of singleton

How to create an array outside of a function, and be able to add to it in other functions

It seems if I do something like:
NSMutableArray *randomSelection = [[NSMutableArray alloc] init];
Then this needs to be in a function, and I can't modify it later using a different function.
I tried just instantiating it in the .h file,
#interface ViewController:
{
NSMutableArray *Values;
}
But then when I try to append to it during runtime, nothing happens. I try to append to it with this:
int intRSSI = [RSSI intValue];
NSString* myRSSI = [#(intRSSI) stringValue];
[Values addObject:myRSSI];
But the array remains empty when I do this.
How can I fix this?
The recommended way is to create a property;
// ViewController.h
#interface ViewController : UIViewController
{
}
#property (nonatomic, strong) NSMutableArray *values;
#end
Then override the getter for that property, to lazy-initialize it, i.e. the array will be allocated and initialized on first call of the NSMutableArray property's getter:
// ViewController.m
#interface ViewController ()
#end
#implementation ViewController
- (NSMutableArray *)values
{
if (!_values) {
_values = [[NSMutableArray alloc] init];
}
return _values;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//int intRSSI = [RSSI intValue];
//NSString *myRSSI = [#(intRSSI) stringValue];
//[self.values addObject:myRSSI];
// Keep it simple:
[self.values addObject:RSSI];
}
#end

Resources