communicating between classes with pointers - objective-c

Hi all,
I'm having a hard time understanding how to use pointers
(my first time using them) hoping someone can point me in the right
direction (no pun intended) :P
(it controls the sound,pagenumber,bg,audio int, and text to be displayed)
(NSString *)textFromPlist pointer which points to the plist containing the text for #"Page01Text"
I want to take #"Page01Text" and use it in the HighLighter class
I am able to log the output for the sound,pagenumber,bg,audio int, and text etc in the hello world layer (its logging the TextManagerWithpageNum) so I know that the plist is reading,
but for some reason I cant link textFromPlist I'd like to be able to use the textFromPlist from the TextManagerWithpageNum class and let the hilighter class work with it (this class will hilight the text and work with the audio intervals supplied by the plist)
this piece of code it returns (NULL)
#interface HighLighter.h
TextManagerWithpageNum *myClassAccess;
//declaring the TextManagerWithpageNum class so I can access textFromPlist
#implementation HighLighter.m
-(NSString *)Sentance01
{
NSString *textFromTextManager = myClassAccess.textFromPlist;
NSString *storyText = [NSString stringWithFormat:#"%#",textFromTextManager];
return [[[NSString alloc]initWithString:StoryText]autorelease];
//doesn't crash but doesn't load text
NSLog(#"text form plist #%",storyText);
}
What is it that I am doing wrong? (I have an int array I also wish to link, but thought I'd start with the NSString as I thought this would be simpler.)
any help would be wonderful, kind regards,
Natalie.
#interface TextManagerWithpageNum : CCLayer
NSString* textFromPlist_Pntr;
#property(nonatomic, readonly) NSString* textFromPlist;
//NSString* textFromPlist is an item on the plist #"page01" which contains text for the page
#property(nonatomic, readonly) NSString* audioInterval;
//NSString* AudioInterval is an array on the plist #"AudioTimings_PG01"
#implementation TextManagerWithpageNum
#synthesize textFromPlist = textFromPlist_Pntr;
#synthesize audioInterval = _audioInterval;

There are a couple of options when communicating any data between classes. I will show both, using an example SomeData object that is being sent from ObjectA to ObjectB. You can also use class level methods to, for example, send or receive data in a pointer to a singleton object. I won't show you how to do that because it doesn't sound like that fits your problem.
Option 1
Define a receiving message in ObjectB.
#interface ObjectA
{
SomeData *someDataPointer;
ObjectB *someObjectB;
}
#end
#implementation ObjectA
-(void)someMethod
{
someDataPointer = [[SomeData alloc] init]; // Or whatever way you want to create and set someDataPointer
[someObjectB receiveData:someDataPointer];
// Note: if you will be calling receiveData on someObjectB much later than the
// time of creation of someDataPointer, you should retain someDataPointer to
// hold onto it until you need to pass it on.
// ie)
// [someDataPointer retain];
}
#end
#interface ObjectB
-(void)receiveData:(SomeData *)dataPtr;
#end
#implementation ObjectB
-(void)receiveData(SomeData *)dataPtr
{
// Here the data from someDataPointer will also be pointed to by dataPtr
// Use dataPtr now
[self doSomethingWithData:dataPtr];
}
#end
Option 2
Define a sending message in ObjectA.
#interface ObjectA
{
SomeData *someDataPointer;
}
#property (nonatomic, retain) SomeData *someDataPointer;
#end
#implementation ObjectA
#synthesize someDataPointer = someDataPointer_;
#end
#interface ObjectB
{
ObjectA *someObjectA;
}
#end
#implementation ObjectB
-(void)someMethod
{
SomeData *dataPtr = [someObjectA getSomeDataPointer];
// Now do something with dataPtr
}
#end
I hope that helps. I wanted to show you these two techniques generally so that you can learn to apply it to your case specifically. Let me know if you have questions.

Related

Variable losing value in delegation pattern

I'm trying to learn about delegation in Objective-C, and am having a minor issue with a variable losing it's data in the transfer process. I have Class1 that contains an NSMutableArray. The array gets populated, then I would like to transfer the array's values to Class2, and display it. Here is the relevant code in Class1:
//Class1.h
#class Class1;
// define the protocol for the delegate
#protocol Class1Delegate
#required
-(void)sayHello:(Class1 *)customClass withAntArray:(NSMutableArray *)antArray;
#end
#interface Class1 : MySuperClassName
#property (nonatomic, assign) id delegate;
-(void)helloDelegate;
#end
//Class1.m:
#interface Class1 ()
#property (nonatomic, strong) NSMutableArray *antOccurenceTimes;
#end
#implementation Class1
#synthesize antOccurenceTimes;
-(void)helloDelegate
{
// send the message to the delegate
[_delegate sayHello:self withAntArray:self.antOccurenceTimes];
}
Now, this is what I have in Class2:
#import "Class1.h"
#interface Class2 : UIView <Class1Delegate>
#end
// Class2.m:
- (void)appropriateTimeToCallMethod {
Class1 *initAntMarks = [[Class1 alloc] init];
initAntMarks.delegate = self;
[initAntMarks helloDelegate];
}
-(void)sayHello:(Class1 *)customClass withAntArray:(NSMutableArray *)antArray {
NSLog(#"Hello! %#", antArray.description);
}
The antArray.description reads as "NULL". Now, I figured that obviously it will be null, because I just created an entirely new instance of the class right before calling upon the needed method. I feel like I may have something mixed up, and being so new to delegation, I'm not sure exactly what. Does anyone know what I need to tweak to utilize Delegation?
I forgot to add that I did initialize it in Class1, and it gets populated just fine. It's only in class2 that this is occurring.
I initalize antOccuranceTimes in a separate method in ClassA in the snippet below, and the NSLog fires twice...
NSLog(#"Array initalized in class A");
antOccurenceTimes = [NSMutableArray new];
Change this line:
#property (nonatomic, assign) id delegate;
to:
#property (nonatomic, weak) id <Class1Delegate> delegate;
assign should only be used for C primitives, not Objective-c object references. You should also be checking if your object actually conforms to the delegate before messaging the delegate.
Edit:
I think you may be confused about the purpose of delegation.
Class1 *initAntMarks = [[Class1 alloc] init];
initAntMarks.delegate = self;
[initAntMarks helloDelegate];
Why are you calling a method on an object which in turn calls a delegate method when you could simply create a method that returns the NSMutableArray? The way you have your code currently set up requires that before the call to -helloDelegate you have to have filled the array with the appropriate objects. The purpose of delegation in MVC is to inform an object about an event that took place inside of another object. You are "delegating" the task off to another object, or you could say, that another object if responsible for the fulfillment of the task. Read the Apple Docs on Delegation. Delegation in your code is not the correct pattern to implement, as I stated you can simply return that array with a method call.
Edit 2:
There are two ways you can achieve this, through property methods or through an explicit method that returns your array. If you choose to use property methods, the property declaration must be in the public interface i.e. the .h file so that your class can all the accessors when the object is being implemented.
//Inside the .h
#property (nonatomic, strong) NSMutableArray *antOccurenceTimes;
This will automatically provide you with two accessor methods for the antOccurenceTimes property. These are the getter -antOccurenceTimes and setter -setAntOccurenceTimes: methods. Now after you initialize the class and fill your array you can call -antOccurenceTimes to return the array.
You can also create an explicit method that return the array:
- (NSMutableArray *)hello{
//Do something here
return _antOccurenceTimes;
}
You have not yet initialized the antOccurenceTimes. Of cause it is nil. There are many options depending on what you need. You can, for example, initialize it in a init function:
- (instancetype)init {
self = [super init];
if( self ) {
antOccurenceTimes = [NSMutableArray array];
[antOccurenceTimes addObject:#"Hello World"];
}
}
Or maybe initialize it before you call the delegate the function.
-(void)helloDelegate
{
// send the message to the delegate
self.antOccurenceTimes = [NSMutableArray array];
[self.antOccurenceTimes addObject:#"Hello World"];
[_delegate sayHello:self withAntArray:self.antOccurenceTimes];
}
I think you get my point.

Spitting out objects from array in Objective-C

I'm quite new to classes and objects and I have a question:
I'm keeping track of books which can be input by textFields.
3 properties per book: Title, Author and Description.
What I'm trying to do is get all the objects of books in a NSMutableArray called: Collection.
(at the moment it's only 1 book (objectAtIndex:0)
Which is currently working but when I try to spit them back out I only get the description of the book. I'd love to get all the items (title, author, description).
What I've been wondering is: should I make a new (collection) class for example called BookCollection and make an array there? But how would I init it etc?
The code is below, help and tips are welcome!
(Started about a month ago)
Book.h
#import <Foundation/Foundation.h>
#interface Book : NSObject
#property(nonatomic,strong)NSString* title;
#property(nonatomic,strong)NSString* author;
#property(nonatomic,strong)NSString* description;
-(id)initWithTitle:(NSString*)newTitle withAuthor:(NSString*)newAuthor andDescription:(NSString*)newDesription;
Book.m
#import "Book.h"
#implementation Book
#synthesize title,author,description;
-(id)initWithTitle:(NSString*)newTitle withAuthor:(NSString*)newAuthor andDescription:(NSString*)newDesription{
self = [super init];
if (self) {
title = newTitle;
author = newAuthor;
description = newDesription;
}
return self;
}
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize lblTitle,lblAuthor,lblDescription;
#synthesize collection;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (IBAction)buttonClick:(id)sender {
//alloc the array that will hold the books
collection = [[NSMutableArray alloc]init];
//create a new book
Book *newBook = [[Book alloc]initWithTitle:[lblTitle stringValue] withAuthor:[lblAuthor stringValue] andDescription:[lblDescription stringValue]];
//logging the items of the book
NSLog(#"%#",newBook.description);
NSLog(#"%#",newBook.title);
NSLog(#"%#",newBook.author);
//adding the book to the collection
[collection addObject:newBook];
//logging the book items from the collection
NSLog(#"%#",[collection objectAtIndex:0]);
//problem... only logs 1 item from the object...
}
#end
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "Book.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property(nonatomic,strong)NSMutableArray *collection;
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSTextField *lblTitle;
#property (weak) IBOutlet NSTextField *lblAuthor;
#property (weak) IBOutlet NSTextField *lblDescription;
- (IBAction)buttonClick:(id)sender;
#end
You need to define your Book class's -description method.
When you call NSLog(#"%#", someObject), the object's -description method gets called and placed inside the %# format specifier. You'll want to override your Book class's -description method to print out all of the object's fields.
Have a look here for a good example.
To clarify, when you call:
NSLog(#"%#",newBook.description);
NSLog(#"%#",newBook.title);
NSLog(#"%#",newBook.author);
You are (quite correctly) logging each individual field. However, when you call:
NSLog(#"%#",[collection objectAtIndex:0]);
You are essentially writing:
NSLog(#"%#",newBook); // Gets an NSString from [newBook description];
And so you need to implement - (NSString *)desctiprion for the Book class to get the logging behaviour you are after.
Step 1 : remove collection = [[NSMutableArray alloc]init]; from - (IBAction)buttonClick:(id)sender and put it into applicationDidFinishLaunching method. Problem is You are initializing your array each time you add New Book to Collection Array.
To Iterate : all the objects of Array use following snippet
[collection enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
Book *objBook = (Book *)obj;
NSLog(#"%#",objBook.description);
NSLog(#"%#",objBook.title);
NSLog(#"%#",objBook.author);;
}];
This Description Method is amazing! I had no idea it was even possible #PLPiper! Thank you
Although it gets harder... at this very moment I'm just logging it all out (for me as a developer). But for example... if I wanted all these properties in labels (string value). So if I wanted to spit them all out through my array, how would that work?
I've seen code that uses the following example(sort of) which I like and it's an easy-read.
for (int i = 0; (i<=[collection.count]); i++) {
[titleLabel setStringValue:[dateCollection objectAtIndex:i].title]
[authorLabel setStringValue:[dateCollection objectAtIndex:i].author]
[descriptionLabel setStringValue:[dateCollection objectAtIndex:i].description]
}
In theory this should work, but in practice I'm missing something here...

Objective-c: Singleton - passing variables

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

Noob needs help designing data model & controller

Disclaimer:
I've been learning Objective C/Cocoa for 2 months or so, and I promised myself that I would always try and find the answer myself rather than clogging the internet with dumb noob questions. At this point I'm just confused all over and I think I would benefit at this point from asking questions. I apologize in advance.
Problem:
I'm trying to write a master-detail style app (this is just for practice) called "My Dream Garage". Basically I want to store car objects and their properties. I have a "Car" class that looks like this:
#import <Foundation/Foundation.h>
#interface Car : NSObject
#property (nonatomic, strong) NSString *brand, *model, *trimLevel;
#property (nonatomic, strong) NSNumber *modelYear, *engineSizeinL, *weight;
#property (nonatomic, strong) id image;
#end
In my main .XIB file I have an NSTableView and a bunch of text labels that will display each property (and an imagewell for the image).
My question is how do I store this data? I understand what NSArray, NSDictionary, ArrayController and DictionaryController are individually. I'm just a little confused on how to make them work together. When I add a new "car", am I supposed to instantiate a new "Car" object with it's properties? At that point do I add the new object to an array and then release the created "Car" object? Do I link the tableview and text-labels to an NSDictionary Controller? I'm not even sure what I should be asking at this point.
Perhaps I'm in a bit over my head. What other than Apple's documentation (which is very good but too verbose for an amateur) would be recommended to learn how to create apps similar to this?
Any help is greatly appreciated. Thank you.
Lots of questions here:
Are you wanting to store them somewhat permanently? If so, you need to start learning Core Data.
What does the implementation file look like for the Car class? How are you (or are you) instantiating and initializing a new object?
My class objects usually look something like this:
Interface:
#interface UserInfo : NSObject {
NSString *_networkID;
NSString *_displayName;
NSString *_userDomain;
BOOL _loggedIn;
}
#property(nonatomic,strong) NSString *networkID;
#property(nonatomic,strong) NSString *displayName;
#property(nonatomic,strong) NSString *userDomain;
#property(nonatomic) BOOL loggedIn;
-(id) initWithUserNetworkID:(NSString *)networkID
displayName:(NSString *)displayName
userDomain:(NSString *)userDomain;
#end
Implementation:
#import "UserInfo.h"
#implementation UserInfo
#synthesize networkID = _networkID;
#synthesize displayName = _displayName;
#synthesize loggedIn = _loggedIn;
#synthesize userDomain = _userDomain;
-(id) initWithUserNetworkID:(NSString *)networkID
displayName:(NSString *)displayName
userDomain:(NSString *)userDomain {
if ((self = [super init])) {
_networkID = [networkID copy];
_displayName = [displayName copy];
_userDomain = [userDomain copy];
_loggedIn = YES;
}
return self;
}
#end
And I will create a new one with code like this:
UserInfo *myUserInfo = [[UserInfo alloc]
initWithUserNetworkID:[loginDictionary objectForKey:#"NetworkID"]
displayName:[loginDictionary objectForKey:#"DisplayName"]
userDomain:[loginDictionary objectForKey:#"UserDomain"]];

Best way to have an application-wide array?

I have a class which contains a method to download data from my server. This is in the form of JSON, but is parsed and put into an array. As this is a 'model' file, what would be the best way to make it so that multiple 'controllers' can access this data?
Hang it off the app delegate, stick it in a global variable, or declare a class method in appropriate spot that returns it.
Better yet, start thinking now about having a proper model layer that, among other things, can manage this data. That will make refactoring easier in the future as your application evolves.
You can create singleton object of class with array object. and by using class method you can get that array any where in app.
e.g.
in Cardnames.h file
#import <Foundation/Foundation.h>
#interface CardNames : NSObject
#property (nonatomic, retain) NSMutableArray *CardNamesArray;
+(CardNames*) getCardsList;
#end
in Cardnames.m file
#import "CardNames.h"
#implementation CardNames
#synthesize CardNamesArray;
static CardNames *cards = nil;
+(CardNames*) getCardsList
{
#synchronized(self)
{
if(cards == nil)
{
cards = [[self alloc] init];
cards.CardNamesArray = [[NSMutableArray alloc] init];
/// code to fill array
}
return cards;
}
}
#end
and in other classes u can use like this
#import "CardNames.h"
.
.
.
NSMutableArray *CardsArray = [[CardNames getCardsList] CardNamesArray];