I have declared an NSMutableDictionary object in AppController.h and initialized in the corresponding AppController.m file.
AppController.h
#import <Cocoa/Cocoa.h>
#interface AppController : NSObject {
NSMutableDictionary *uberDict;
}
AppController.m
#import "AppController.h"
#implementation AppController
- (id)init
{
uberDict = [NSMutableDictionary new];
return self;
}
Now I want to use the NSMutableDictionary object in another view, flashcardView. I add/remove items in the dictionary using methods in the AppController class and want to use the same dictionary (with the current items still present in it) in the flashcardView view. The problem is that I don't know how to access the dictionary object from outside AppController. How would I do that?
from flashcardView.m
- (void)setAndCheckString
{
NSArray *keys = [uberDict allKeys];
NSString *i;
for (i in keys) {
string = i;
NSLog(#"%#", string);
}
}
Here's where the problem lies. What do I do with uberDict to make this work? Thanks!
While I encourage you to look at alternative design patterns, to do what you're looking for you simply need to add a method (or property) to access uberDict to AppController. As a property, the code would be:
#interface AppController : NSObject {
NSMutableDictionary *uberDict;
}
#property (readonly) NSMutableArray *uberDict;
#end
in the AppController.h file, and just add a one line #synthesize uberDict; inside the AppContoller implementation (before the #end). Don't worry about the (readonly) -- this means that the object getting the uberDict cannot set it to a new dictionary, but still can modify the contents of the dict and read from it.
Related
I have a cocoa application that I'm trying to make scriptable. It has a model class (subclass of NSObject) including an NSArray property, which holds a number of custom "Element" objects of a separate class. I like this design pattern for this application, because the array property for the model class is not needed outside of that class (and thus I don't want to include it in a subclass/category of NSApplication). However, in all of the examples I have seen for creating a scriptable Cocoa application, the top level scripting object is a subclass or category of NSApplication that includes the exposed data as a property or element.
In contrast, I don't have any properties or methods in NSApplication. As a simplified example, see the code below (from DataModel.h/DataModel in my project):
#import <Foundation/Foundation.h>
#import "Element.h"
#interface DataModel : NSObject
#property (nonatomic) NSArray *elements;
#end
#implementation DataModel
#synthesize elements = _elements;
- (id)init {
if (self= [super init]) {
Element *element1 = [[Element alloc] init];
element1.elementName = "first element";
element1.elementNumber = "22";
Element *element2 = [[Element alloc] init];
element2.elementName = "second element";
element2.elementNumber = "24";
self.elements = [NSArray arrayWithObjects:element1, element2, nil];
}
return self;
}
#end
and this code (for Element.h/Element.m - the objects stored in the "elements" NSArray of the ViewController:
#import <Foundation/Foundation.h>
#interface Element : NSObject {
}
#property (nonatomic) NSString *elementName;
#property (nonatomic) NSString *elementNumber;
#end
#import "Element.h"
#implementation Element
#synthesize elementName = _elementName, elementNumber = _elementNumber;
#end
When the data model is it's own class, how do I make "elements" an accessible property in my sdef file? Do I need an object specifier in the DataModel or the Element class? NSApplication contains no properties, elements, or commands in this case.
Thanks!
I have an academic question about Class Method exposure. There is something that I obviously don't understand about this and would like some clarification from those in the know.
Background:
I have a simple example of two classes named ViewController and ClassB. Class B contains an array with a method named returnArray. The ViewController accesses the array's data. I have exposed the returnArray method in the ClassB.h file.
Question:
Why is it that I can access the array's data in ViewController without having to define a property? I thought that the property would create a getter to allow access to the array. My example (only exposing the method) allows me to access the data without the creation of the #property.
Class Method:
ClassB.h
#interface ClassB : UIViewController
+(NSArray *) returnArray;
//#property (nonatomic, strong) NSArray *returnArray;
ClassB.m
#implementation ClassB
+(NSArray *) returnArray
{
NSArray *locationArray = #[#"Place1", #"Place2"];
return locationArray;
}
ViewController.m
- (void)viewDidLoad
{
NSArray *location = [ClassB returnArray];
NSLog (#"The count of the location is %d", [location count]);
NSLog (#"The second item in testArray is %#", location[1]);
}
Instance method: After reviewing answers
ClassB.h
*/
{
#private
NSArray *returnArray;
}
- (void)setReturnArray:(NSArray*)returnArray;
-(NSArray *) returnArray;
*/
#property (nonatomic, strong) NSArray *returnArray;
#end
ClassB.m - no change
ViewController.h - no change
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Create instance of ClassB
ClassB *classB = [ClassB new];
//Access the instance of returnArray
NSArray *location = [classB returnArray];
NSLog (#"The count of the location is %d", [location count]);
NSLog (#"The second item in testArray is %#", location[1]);
}
#property is a shorthand notation for creating an instance variable and associated accessor methods (with defined access / modification criteria).
What you have is a class method, which internally creates an array and returns it.
That's why you call [ClassB returnArray]; instead of [instanceOfB array];.
These are completely different things. If you wanted to use a property then you would need to create an instance of ClassB and then access the property. This would work, assuming that the array was created when the instance of ClassB was created.
Wain's answer addresses the difference between #property and Class methods, so it's worth a read. My answer assumes you know the difference between class and instance methods, and focuses on the difference between creating a #property versus creating an instance variable with an associate setter and getter.
The reason is because returnArray is a public method that returns an NSArray object on your ClassB.
A #property is merely a convenient way of creating three things at the same time: an instance variable, a setter, and a getter. It has the added bonus of allowing dot-syntax.
But at the end of the day, dot-syntax aside, all you're doing by declaring a #property is equivalently equal to this:
#interface ClassB : NSObject {
#private
NSArray *returnArray;
}
- (void)setReturnArray:(NSArray*)returnArray;
- (NSArray*)returnArray;
This is the same as this:
#property NSArray *returnArray;
Except of course, the dot syntax.
When you do:
NSArray *myArray = classB.returnArray;
You're not actually directly accessing the array you created when you declared the #property.
What you're doing is calling the getter method that was automatically generated when you declared the #property.
I have a singleton that I'd like to use to manage the onscreen animation of my views. Here's my.
#import <Foundation/Foundation.h>
#interface OAI_AnimationManager : NSObject {
NSMutableDictionary* sectionData;
}
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
.m file
#import "OAI_AnimationManager.h"
#implementation OAI_AnimationManager
#synthesize sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
static OAI_AnimationManager* sharedAnimationManager;
#synchronized(self) {
if (!sharedAnimationManager)
sharedAnimationManager = [[OAI_AnimationManager alloc] init];
return sharedAnimationManager;
}
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", sectionData);
}
#end
You'll see in the .h file I added a NSMutableDictionary and am using #property/#synthesize for it's getter and setter.
In my ViewController I instantiate the animation manager as well as a series of subclasses of UIView called Section. With each one I store the data (x/y w/h, title, etc.) in a dictionary and pass that to the dictionary delcared in animation manager. In the Section class I also instantiate animation manager and add a UITapGestureRecognizer which calls a method, which passes along which section was tapped to a method (checkToggleStatus) in animation manager.
As you can I see in the method I am just logging sectionData. Problem is I am getting null for the value.
Maybe my understanding of singletons is wrong. My assumption was the class would only be instantiated once, if it was already instantiated then that existing object would be returned.
I do need all the other Section classes data as if one animates others animate in response and I can get around it by passing the tapped Section to the animation manager and doing [[Section superview] subviews] and then looping and getting the data from each that way but it seems redundant since that data is available in the ViewController when they are created.
Am I doing something wrong in trying to transfer that data? Is there a better solution? I am open to suggestions and criticisms.
Thanks
h file
#interface OAI_AnimationManager : NSObject
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
m file
static OAI_AnimationManager* _sharedAnimationManager;
#implementation OAI_AnimationManager
#synthesize sectionData = _sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
#synchronized(self) {
if (!_sharedAnimationManager) {
_sharedAnimationManager = [[OAI_AnimationManager alloc] init];
}
}
return _sharedAnimationManager;
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", _sectionData);
}
#end
Notice I moved your sectionData variable from the header and moved it to the implementation file. A while back, they changed it to where you can synthesize properties and specify their instance variable names along side it... hence:
sectionData = _sectionData;
I also added and underscore to the instance variable... this is a universal convention for private variables and it also will throw a compile error now if you try to type just sectionData as you did in the return statement of checkToggleStatus:. Now you either have to type self.sectionData or _sectionData.
You didn't include the code that creates an instance of your dictionary but I bet you didn't set it as self.sectionData = [[NSDictionary alloc] init] which means it would not retain the value and you would get null the next time you called it. Classic memory management mistake... I know it well because I learned the hard way hehehe
I have a Cocoa project with an object that holds information from a SQLite database.
By now the information is stored in memory by this object and is used in the user interface to read and write new information.
But now I came to a small problem... I decided to create a new controller class to handle the actions of an NSTableView and I want to access this same database object that was declared elsewhere.
Which is the best option to access this information? I wish to avoid loading the information more than once in memory and also avoid use pure C/C++ codes with global variables.
It is better to understand my point by looking at the code.
I accept other solutions as well, naturally.
My idea of code is currently like this:
FirstClass.h
#import <Foundation/Foundation.h>
#import "DatabaseModel.h"
#interface FirstClass : NSObject {
IBOutlet NSScrollView *informationListTable;
NSMutableArray *informationList;
}
#end
FirstClass.m
#import "FirstClass.h"
#implementation FirstClass
- (void)awakeFromNib{
DatabaseModel *list = [[DatabaseModel alloc] init];
informationList = [[NSMutableArray alloc] initWithArray:[list loadList]];
[list release];
[machinesListTable reloadData];
}
SecondClass.h
#import <Foundation/Foundation.h>
#interface SecondClass : NSObject {
IBOutlet NSTextField *labelName;
NSString *name;
}
- (IBAction)showName:(id)sender;
#end
SecondClass.m
#import "FirstClass.h"
#import "SecondClass.h"
#implementation SecondClass
- (IBAction)showName:(id)sender{
/*
Here name must get something like:
[[FirstClass.informationList objectAtIndex:3] name]
Here labelName must display name.
*/
}
#end
you can either create the object once then pass the object around, with each controller retaining it as needed. Or you can use a singleton instance. I would say the singleton instance is easier to read, but it depends on the application
One solution would be to make FirstClass a singleton. Then, anywhere else in your code, you could call [FirstClass sharedInstance] (replace sharedInstance with the name you'll give to your class method) and use this object. You'll have to be careful about concurrency issues though.
Having some difficulty with what I thought would be straight forward. I am trying to make an array of class objects but running into different problems. The goal was to create one class that held an array of another class of objects.
Any help appreciated:
// Basic class unit
#interface MobRec : NSObject {
NSString *MName;
int Speed;
}
#end
// Master Class holding an array of units
#interface MobDefs : NSObject {
MobRec *MobInfo;
}
#property(retain) MobRec *MobInfo;
#end
#synthesize MobInfo;
1) From reading it seems I should create and NSMutableArray but how do you declare an NSMutableArray of custom class objects? All iterations I try cause errors. Previously I had predefined the size in the class as MobInfo[20]; but that didnt seem to be good for anything.
2) How do you properly #Synthesize an array of class objects?
I think you misunderstand what #synthesize does. It creates accessor methods to get and set the property (i.e., it would create a getter method to return that NSMutableArray and a setter method to allow you to replace it with another NSMutableArray). To create an NSMutableArray, you would just create one like any other object in that class's initializer.
NSMutableArray doesn't have any type checking as you add (or read) from it, so you can add any objects you want to it.
In this case I'd have something like:
// MobRec Class
#interface MobRec : NSObject {
NSString *mName;
int speed;
}
#property(retain)NSString *name;
#property(assign)int speed;
#end
#implementation MobRec
#synthesize mName, speed;
#end
// MobDefs Class
#import "MobRec.h"
#interface MobDefs : NSObject {
NSMutableArray *mobInfo;
}
#property(retain) NSMutableArray *mobInfo;
#end
#implementation MobDefs
#synthesize mobInfo;
- (id)init {
mobInfo = [[NSMutableArray alloc] init];
MobRec *aNewMobRec = [[MobRec alloc] init];
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
}
I've included the basics for adding to the array as well so you can see how its used. Oh and don't forget you have to release the MobInfo in the dealloc method.
But mostly look at NSMutableArray
Your MobDefs class is not necessary, you can use an NSMutableArray directly. NSArray can hold objects of any type, and is declared in just the same way as any other object (such as your MName property).