I was wondering how can I share a NSDictionary objects among several view controllers which basically are tabs in my application.
I tried using a protocol, like in Java, so that I can cast to the protocol and access the property. That doesn't seem to work.
Also I had a look at similar question at
How to share data globally among multiple view controllers
But I observed that the appDelegate method is not safe and may lead to memory leak.
Similarly injection on class A into class B will create the same problem.
So can anyone suggest me any method which i should study or implement in my code?
If you wants to share only Dictionary, why don't you go for class method using from helper class.
+(NSDictionary *)shareMethod
{
return dict;
}
You can use singleton class for sharing the data
Check this Singleton class
MyManger.h
#import <foundation/Foundation.h>
#interface MyManager : NSObject {
NSMutableDictionary *_dict
}
#property (nonatomic, retain) NSMutableDictionary *dict;
+ (id)sharedManager;
#end
MyManger.m
#import "MyManager.h"
static MyManager *sharedMyManager = nil;
#implementation MyManager
#synthesize dict = _dict;
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if(sharedMyManager == nil)
sharedMyManager = [[super allocWithZone:NULL] init];
}
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
dict = [[NSMutableDictionary alloc] init];
}
return self;
}
You can access your dictionary from everywhere like this
[MyManager sharedManager].dict
I found a way out. Since I want a dictionary to be shared across, I declared a method in my protocol
- (void) setSingleHouse:(NSDictionary*) singleHouse;
In each of my controller I implemented the method in a appropriate manner. Hence I was able to share across them for now.
Also I figured out that I was casting in a wrong way earlier i.e (#protocol(protocol name)). Now changed it into NSObject .
Sorry for the fuss.
I advise you not to use a property in your appDelegate instance. This pattern doesn't improve code reusability.
Basicly your shared NSDictionnary is your model. So, if you want your code to follow the MVC design parttern, you should create a class with a shared instance that would contain your NDDictionnary in a public property.
This is well explained in this post
This way, you will access your shared NSDictionnary this way
:
NSDictionary* sharedDictionnary = [MyModel sharedInstance].sharedDictionary;
Related
I know how to implement UISearchController for a table view. But can anyone help me in implementing search bar for complete app.
In my app i have 3 view controllers
a)students VC
b)teachers VC
c)parents VC
and I have a search button. Here i want to implement complete in app search functionality. If we type in a name it should appear in a table view either it is in students/parents/teachers. I am not getting any idea how to start this. Please give some KT.
I just try to create singleton class that store value and use as a global. So first you need to create a Singleton-class using following code:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject
{
NSMutableArray *ClassArray;
}
+(GlobalData *) getInstance;
-(void)saveClassARray:(NSArray *)array;
-(NSMutableArray *)getGlobalArray;
#end
It's .M Class
#import "GlobalData.h"
#implementation GlobalData
static GlobalData *instanceGlobalData;
+(GlobalData *) getInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instanceGlobalData = [[GlobalData alloc] init];
instanceGlobalData->ClassArray = [[NSMutableArray alloc]init];;
});
return instanceGlobalData;
}
-(void)saveClassARray:(NSArray *)array
{
[ClassArray addObjectsFromArray:array];
}
-(NSMutableArray *)getGlobalArray
{
return ClassArray;
}
#end
Now you need to store your Students, Teachers and Parents data by following code.
First you need to import #import "GlobalData.h" in your ViewController and create define variable that like following:
#import "GlobalData.h"
#define USERDATASINGLETON (GlobalData *)[GlobalData getInstance]
And in Web services Call back Success you need to store your data in globle array using following code:
NSArray *array =[[NSArray alloc]initWithObjects:#"Nitin",#"Nit", nil];
[USERDATASINGLETON saveClassARray:array];
Above array is just for your referance do same things for all your 3 ViewController and store the result using saveClassARray. now finally you need to get full array by following code:
NSMutableArray *FinalGlobalArray = [USERDATASINGLETON getGlobalArray];
NSLog(#"==%#",FinalGlobalArray);
That will be NSlog allof the data that have you stored. but make sure use some check that once you add teacher,student,parents data and if saveClassARray calling again that old data wont be overtire that will be create duplicate entry so take care about.
Now you have finalArray you can do your search code that you have did for individual.
Hope that help
I need an app or an online converter like JSON Accelerator that generates Objective C classes from JSON strings. I had some issues with this app, some JSON's are converted OK others are not. There are a lot of properties, it would take ages to write them down manually and use tools like JSON Model or similar. Thanks in advance.
You are much better off creating a class that can be initialized from an NSDictionary and that way you can parse the JSON to an NSDictionary, in the traditional way, and then create your class from that dictionary. You can also create arbitrary instances of the custom class and initialize the properties piece-meal.
#interface MyClass : NSObject
#property NSString *name;
#property NSUInteger age;
- (instancetype)initWithDictionary:(NSDictionary *)dict;
#end
#implementation MyClass
- (instancetype)initWithDictionary:(NSDictionary *)dict
{
self = [super init];
if (self) {
_name = dict[#"name"];
_age = [dict[#"age"] unsignedInteger];
}
return self;
}
#end
you can use thus toll to get objc object from json
http://www.realmgenerator.eu/
and also you can use these mapper to get our result
https://github.com/aryaxt/OCMapper
There are many questions concerning the category-properties problem.
I know some possibilities to address this:
use a singleton registry
objc_setAssociatedObject and objc_getAssociatedObject
From my point of view both is not clean since the memory allocated is never cleared when the object that created such properties is deallocated.
Categories are a good way to keep code clean and dynamically add functionality to already existing classes. They help to group functionality and to distributed implementation work among more developers.
The bad about categories is the missing storage.
I came across this problem several times now and I'm wondering whether the following would address this problem in an clean way that also takes care about the memory and if there are any problems that I can't see right now.
There is one restriction, that I can ignore since I'm working as a framework developer: I'm able to create my own root class that all my other classes can inherit from.
First of all declare the new root object:
#interface RootObject : NSObject
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key;
- (id)runtimePropertyForKey:(id)key;
#end
With the corresponding implementation:
#import "RootObject.h"
#interface RootObject ()
#property (readwrite) NSMutableDictionary *runtimeProperties;
#end
#implementation RootObject
#synthesize runtimeProperties = _runtimeProperties;
- (id)init {
self = [super init];
if (self)
{
_runtimeProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return self;
}
- (void)dealloc {
[_runtimeProperties release];
_runtimeProperties = nil;
[super dealloc];
}
- (id)runtimePropertyForKey:(id)key {
return [self.runtimeProperties objectForKey:key];
}
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key {
if (key)
{
if (runtimeProperty)
{
[self.runtimeProperties setObject:runtimeProperty forKey:key];
}
else
{
[self.runtimeProperties removeObjectForKey:key];
}
}
}
#end
By using this RootObject instead of NSObject it should be very easy to add a "property" to a category on a class. Consider having some class MyClass
#interface MyClass : RootObject
// some interface here
#end
When implementing a special behavior on top of this class you are now able to add a property like this:
#interface MyClass (specialBehavior)
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSDate *birthday;
#end
With corresponding implementation:
#implementation MyClass (specialBehavior)
#dynamic name;
- (NSString *)name {
return [self runtimePropertyForKey:#"name"];
}
- (void)setName:(NSString *)name {
[self setRuntimeProperty:name forKey:#"name"];
}
#dynamic birthday;
- (NSDate *)birthday {
return [self runtimePropertyForKey:#"birthday"];
}
- (void)setBirthday:(NSDate *)birthday {
[self setRuntimeProperty:[birthday copy] forKey:#"birthday"];
}
#end
Such an implementation could KVO compatible as well by just adding the necessary calls in the setter method.
Very straight forward, but I'm wondering whether I missed something important? (E.g. very very bad runtime performance having many such declared properties or using many of these objects)
This is effectively the same as objc_setAssociatedObject and objc_getAssociatedObject, which do release memory when the object is deallocated (depending on the association type). I would guess they also have much lower overhead than your suggested code.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 9 years ago.
I need to make one instance of an array that can be access by multiple view controllers. It will contain objects that will be displayed in a table view and created by a modular view and then displayed in the table view. I can't figure out how to access it once I make a #property for it in the main view controller or the AppDelegate class.
You should make a singleton and the recommended way to do that in objective-c is to create a class and add a method that looks something like:
+ (YourClass *)sharedYourClass
{
static dispatch_once_t onceToken;
static YourClass *sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Put the array as a property in your class.
//YourClass.h
#interface YourClass : NSObject
#property(nonatomic, strong)NSArray *yourArray;
+(YourClass *)sharedYourClass;
#end
And in every class you want to use your singleton start by importing YourClass.h and then use it like:
NSArray *arr = [YourClass sharedYourClass].yourArray;
[YourArray sharedYourClass].yourArray = [[NSArray alloc] init];
etc..
What I do is put the data I want shared, in your instance the array, in the AppDelegate. Then I define a protocol that the app delegate conforms to. This lets me access the data anywhere. For example, say I have an array I want everywhere:
First define a protocol:
#protocol ApplicationState<NSObject>
#property(nonatomic, strong) NSArray* data;
#end
Then make your app delegate conform to it:
#interface AppDelegate : UIResponder <UIApplicationDelegate, ApplicationState>
#property (strong, nonatomic) UIWindow *window;
#property(nonatomic, strong) NSArray* data;
#end
Then reading and writing this shared object is simple:
id<ApplicationState> appState = (id<ApplicationState>) [UIApplication sharedApplication].delegate;
appState.data = [[NSArray alloc] init];
I am going to assume you can make the class of the array inherit from NSObject, and then pass it to the View Controller from there...
You have 2 ways to do this:
1.- Instantiate 1 arra on the main class and pass the reference to each viewcontroller what you need.
2.- Make a singleton class to hold the array an use this in your project.
First create a class like this
//GlobalDataClass.h
#interface GlobalDataClass : NSObject
#property(nonatomic,retain)NSArray *myArray;
+(GlobalDataClass*)getInstance;
#end
#import "GlobalDataClass.h"
//GlobalDataClass.m
#implementation GlobalDataClass
#synthesize myArray;
static GlobalDataClass *instance =nil;
+(GlobalDataClass *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance = [GlobalDataClass new];
}
}
return instance;
}
#end
Then you can use it in your viewControllers like this:
-(void)viewDidLoad{
[super viewDidLoad];
self.dataObj = [GlobalDataClass getInstance];
NSLog(#"%#",self.dataObj.myArray);
}
Hope it helps!
Trying to extend the capabilities from a open source project, I wrote a category for add a new method. In this new method, the category needs to access to an internal method from the original class, but the compiler says that it can't find the method (of course, is internal). Is there any way to expose this method for the category?
EDIT
I don't want to modify the original code, so I don't want to declare the internal method in the original class header file.
The code
In the original class implementation file (.m), I have this method implementation:
+(NSDictionary*) storeKitItems
{
return [NSDictionary dictionaryWithContentsOfFile:
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:
#"MKStoreKitConfigs.plist"]];
}
In the category, I want to add this method:
- (void)requestProductData:(NSArray *(^)())loadIdentifierBlock
{
NSMutableArray *productsArray = [NSMutableArray array];
NSArray *consumables = [[[MKStoreManager storeKitItems] objectForKey:#"Consumables"] allKeys];
NSArray *nonConsumables = [[MKStoreManager storeKitItems] objectForKey:#"Non-Consumables"];
NSArray *subscriptions = [[[MKStoreManager storeKitItems] objectForKey:#"Subscriptions"] allKeys];
if(loadIdentifierBlock != nil) [productsArray addObjectsFromArray:loadIdentifierBlock()];
[productsArray addObjectsFromArray:consumables];
[productsArray addObjectsFromArray:nonConsumables];
[productsArray addObjectsFromArray:subscriptions];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
In every line in which I call storeKitItemscompiler says: Class method "+storeKitItems" not found ...
This is trivial, make a forward declaration of the method.
Unfortunately, in obj-c, every method declaration must be inside #interface, so you can make it work in your category .m file with another internal category, e.g.
#interface MKStoreManager (CategoryInternal)
+ (NSDictionary*)storeKitItems;
#end
No implementation is needed, this only tells the compiler the method is somewhere else, similarly to #dynamic with properties.
If you are only interested in removing the warning, you can also just cast the class to id, the following should work, too:
NSDictionary* dictionary = [(id) [MKStoreManager class] storeKitItems];
However, my favorite solution is to do it a bit differently, let's assume the following example:
#interface MyClass
#end
#implementation MyClass
-(void)internalMethod {
}
#end
#interface MyClass (SomeFunctionality)
#end
#implementation MyClass (SomeFunctionality)
-(void)someMethod {
//WARNING HERE!
[self internalMethod];
}
#end
My solution is to split the class into two parts:
#interface MyClass
#end
#implementation MyClass
#end
#interface MyClass (Internal)
-(void)internalMethod;
#end
#implementation MyClass (Internal)
-(void)internalMethod {
}
#end
And include MyClass+Internal.h from both MyClass.m and MyClass+SomeFunctionality.m
A category has no access to the private methods of a class. It's no different than trying to call those methods from any other class. At least if you call the private method directly. Since Objective-C is so dynamic, you can call private methods (which is a bad idea) using other means such as using performSelector or with NSInvocation.
Again, this is a bad idea. An update to the implementation of the class could break your category.
Edit: Now that there is code posted -
Since the +storeKitItems method is not declared in the .h file, no category or other class can access the private method.
In you category implementation file you can define and informal protocol for the method
#interface YourClasses (ExternalMethods)
+(NSDictionary*) storeKitItems;
#end
This will stop the compiler from complaining about not knowing of the method storeKitItems in you category.