Hi am a experienced Java programmer.I've just stepped into learning Objective-C and XCode.I am unable to understand
a very basic but important thing which is not letting me progress any further.
I want to create objects of classes defined by me and then access and use those objects in the View Controller methods of different
Views in the Storyboard.
I don't know where and how to create the objects so they could be accessed in any View.In Java I can do everything in main but the
structure of Objective C is confusing me.
For example I have a class
#interface list : NSObject
{
NSMutableArray* ary;
}
#end
I want to create objects of this class and use them those objects in the methods of different View Controllers.
How can I do so?
Please can somebody just give me a to the point answer about where to create the objects so they could become accessible in View Controller methods.
I have seen far to complex answers but not basic ones
PS: I'm using XCode 4.4
I think you should read some books or tutorials.
Some books:
http://www.amazon.com/Programming-Objective-C-5th-Developers-Library/dp/032188728X/ref=sr_1_3?s=books&ie=UTF8&qid=1351547991&sr=1-3&keywords=stephen+kochan
http://www.amazon.com/Learn-Objective-C-Java-Developers-Series/dp/1430223693
http://www.amazon.com/Objective-C-Absolute-Beginners-iPhone-Programming/dp/1430228326
For tutorial - just google it - one of them:
http://mobile.tutsplus.com/tutorials/iphone/learn-objective-c-day-1/
Say, you have mainViewController class where you want to use your list class then you can do something as follows:
// mainViewController.h
#import "list.h"
#interface mainViewController
#property (nonatomic, strong) list *objList;
#end
// mainViewController.m
#implementation mainViewController
#synthesize objList = _objList;
- (void) viewDidLoad {
self.objList = [[list alloc] init];
}
- (void) someMethod {
self.objList.ary = ...;
}
#end
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have a problem that I hope you can help me with. I have an app with several storyboard views, each with a separate viewcontroller. I want to be able to use my own class in all views in the storyboard. This will make the code in each viewcontroller much cleaner and the whole app easier to debug etc. The class will contain variables and methods.
The overall aim for me is to collect data from the user via buttons and then store these in a database. It will be possible to view and amend data, as well as generating statistics.
As most variables and methods will be used in different views and at different times, I would like to separate all these in separate files.
I can also tell you that this is not a lazy short-cut attempt from me, I have surfed the internet for many, many hours reading hundreds of posts etc and I am still nowhere nearer a solution.
Any input is very much appreciated!
Thank you for taking your time to read this...
SomeClass.h has the following code:
#import <Foundation/Foundation.h>
#interface SomeClass : NSObject
{
NSString *dataOne;
NSString *dataTwo;
NSString *dataThree;
}
- (void) SetDataOne: (NSString*) dataOneReceived;
- (void) SetDataTwo: (NSString*) dataTwoReceived;
- (void) SetDataThree: (NSString*) dataThreeReceived;
- (void) saveSomeData;
#end
SomeClass.m has the following code:
#import "SomeClass.h"
#implementation SomeClass
- (void) SetDataOne: (NSString*) dataOneReceived {
dataOne = dataOneReceived;
}
- (void) SetDataTwo: (NSString*) dataTwoReceived {
dataTwo = dataTwoReceived;
}
- (void) SetDataThree: (NSString*) dataThreeReceived {
dataThree = dataThreeReceived;
}
- (void) saveSomeData {
// Here I do stuff with dataOne etc…
}
#end
SomeView.h has the following code:
#import <UIKit/UIKit.h>
#import "HeadViewController.h"
#import "SomeClass.h"
#interface SomeView : UIViewController
// contains stuff not needed to show here
- (IBAction)Done:(id)sender;
#end
SomeView.m has the following code:
#import "SomeView.h"
#import "SomeClass.h"
#interface SomeView ()
#end
#implementation SomeView
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClassObject = [[SomeClass alloc] init];
// Do any additional setup after loading the view.
}
// Other standard methods omitted
- (IBAction)Done:(id)sender {
[someClassObject SetDataOne: #”whatever text”];
[someClassObject SetDataTwo: #”whatever text”];
[someClassObject SetDataThree: #”whatever text”];
[someClassObject SaveSomeData];
Error Msg for all the above: ”Use of Undeclared Identifier ’someClassObject’
}
#end
Comment: You can see the error message I get at the end of the code above. I have no clue what I am doing wrong. I have looked at a lot of examples on how to create and call classes, but cannot seem anything that solves my problem. Also, I see that some of the put the ”SomeClass *someClassObject = [[SomeClass alloc] init];” in the ”main.m file”. If I understand correctly, that file is the first one to load when app starts. If so, then I cannot place it there as I will have to create instances of my class in several different views and other times than when the app starts. That is why I have placed it in the viewDidLoad-method.
A couple of thoughts:
You've made someClassObject a local variable of the viewDidLoad method. Looks like you meant to make it a class instance variable (or, better, a private class property, which will have the instance variable synthesized for you). Thus:
#interface SomeView ()
#property (nonatomic, strong) SomeClass *someClassObject;
#end
#implementation SomeView
- (void)viewDidLoad
{
[super viewDidLoad];
self.someClassObject = [[SomeClass alloc] init];
}
- (IBAction)done:(id)sender {
[self.someClassObject setDataOne: #"whatever text"];
[self.someClassObject setDataTwo: #"whatever text"];
[self.someClassObject setDataThree: #"whatever text"];
[self.someClassObject saveSomeData];
// should resolve the Error Msg for all the above: ”Use of Undeclared Identifier ’someClassObject’
}
BTW, as a matter of convention, your method names should start with a lowercase letter (e.g. setDataOne not SetDataOne, done rather than Done, etc.), as illustrated above.
If you're going to write your own setters, setDataOne, setDataTwo, etc., you might as well remove those three instance variables, remove your three setData___ methods, and replace the three instance variables with class properties (and let the compiler synthesize not only the instance variables, but the setters, too).
someClassObject is set inside viewDidLoad and because it is not stored anywhere inside the view will be deleted at the end of that very same method
You should add your object inside each header file's interface section like this:
SomeView.h
#import <UIKit/UIKit.h>
#import "HeadViewController.h"
#import "SomeClass.h"
#interface SomeView : UIViewController
{
SomeClass *someClassObject;
}
// contains stuff not needed to show here
- (IBAction)Done:(id)sender;
#end
Then when you instantiate someClassObject inside ViewDidLoad it will persist throughout that view.
SORRY FOR THE LENGTH OF THIS POST; IT IS MEANT TO DOCUMENT MY JOURNEY WITH THIS PROBLEM.
I have a question about a shared object in a Cocoa app that needs to change from time to time and how best to store it so that it's accessible from a few different places. Bear with me.
Class Implementation
The shared object is implemented as a Class Cluster (i.e., https://stackoverflow.com/a/2459385/327179) that looks like the following (note that Document is merely a class name; it is not necessarily indicative of what my actual class does):
In Document.h:
typedef enum {
DocumentTypeA,
DocumentTypeB
} DocumentType;
#interface Document : NSObject {}
- (Document *) initWithDocumentType:(NSUInteger)documentType;
- (void) methodA;
- (void) methodB;
#end
In Document.m:
#interface DocumentA : Document
- (void) methodA;
- (void) methodB;
#end
#interface DocumentB : Document
- (void) methodA;
- (void) methodB;
#end
#implementation Document
- (Document *)initWithDocumentType:(NSUInteger)documentType;
{
id instance = nil;
switch (documentType) {
case DocumentTypeA:
instance = [[DocumentA alloc] init];
break;
case DocumentTypeB:
instance = [[DocumentB alloc] init];
break;
default:
break;
}
return instance;
}
- (void) methodA
{
return nil;
}
- (void) methodB
{
return nil;
}
#end
#implementation DocumentA
- (void) methodA
{
// ...
}
- (void) methodB
{
// ...
}
#end
#implementation DocumentB
- (void) methodA
{
// ...
}
- (void) methodB
{
// ...
}
#end
How The User Interacts with a Document
Via a menu item, the user can switch between DocumentA and DocumentB at will.
What Happens When A "Switch" Occurs
When the user switches from, say, DocumentA to DocumentB, I need two things to happen:
My primary NSViewController (MainViewController) needs to be able to use the new object.
My AppDelegate needs to update an NSTextField that happens to be located in the content border of the main window. (FWIW, I can only seem to assign an outlet for the NSTextField in the AppDelegate)
The Question(s)
I've seen singletons mentioned quite a bit as a way to have a global reference without cluttering up one's AppDelegate (primarily here and here). That said, I've not seen much info on overwriting such a singleton (in our case, when a user switches from DocumentA to DocumentB [or vice versa], this global reference would need to hold the new object). I'm not an expert on design patterns, but I do remember hearing that singletons are not meant to be destroyed and recreated...
So, given all this, here are my questions:
How would you store my Class Cluster (such that MainViewController and AppDelegate can access it appropriately)?
Am I mixing concerns by having both MainViewController (who uses Document heavily) and AppDelegate (who manages the primary window [and thus, my NSTextField]) have knowledge of Document?
Feel free to let me know if I'm thinking about this problem incorrectly; I want this implementation to be as orthogonal and correct as possible.
Thanks!
Status Update #1
Thanks to advice from #JackyBoy, here's the route I've taken:
Document is the one that, upon "switching", "notifies" AppDelegate and MainViewController by passing them the newly created instance.
Both AppDelegate and MainViewController can update the Document object via the Singleton instance as necessary.
Here are my new files (dumbed down so that y'all can see the crux of the matter):
In Document.h:
#import <Foundation/Foundation.h>
#class AppDelegate;
#class MainViewController;
typedef enum {
DocumentTypeA,
DocumentTypeB
} DocumentType;
#interface Document : NSObject
#property (weak, nonatomic) MainViewController *mainViewControllerRef;
#property (weak, nonatomic) AppDelegate *appDelegateRef;
+ (Document *)sharedInstance;
- (id)initWithParser:(NSUInteger)parserType;
#end
In Document.m:
#import "AppDelegate.h"
#import "Document.h"
#import "MainViewController.h"
#interface DocumentA : Document
// ...
#end
#interface DocumentB : Document
// ...
#end
#implementation Document
#synthesize appDelegateRef;
#synthesize mainViewControllerRef;
+ (Document *)sharedInstance
{
static XParser *globalInstance;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
// By default, I return a DocumentA object (for no particular reason).
globalInstance = [[self alloc] initWithDocumentType:DocumentA];
});
return globalInstance;
}
- (id)initWithDocumentType:(NSUInteger)documentType
{
Document *instance = nil;
switch (parserType) {
case DocumentTypeA:
instance = [[DocumentA alloc] init];
break;
case DocumentTypeB:
instance = [[DocumentB alloc] init];
break;
default:
break;
}
// QUESTION: Is this right? Do I have to store these references
// every time a new document type is initialized?
self.appDelegateRef = (AppDelegate *)[NSApp delegate];
self.mainViewControllerRef = self.appDelegateRef.mainViewController;
[self.appDelegateRef parserSwitchedWithParser:instance];
[self.mainViewControllerRef parserSwitchedWithParser:instance];
return instance;
}
#end
#implementation Xparser_NSXML
// ...
#end
#implementation DocumentA
// ...
#end
Should I be bothered by the fact that Document has knowledge of the existence of AppDelegate and MainViewController? Additionally, should I be bothered by the fact that when the Document object updates, it re-notifies both AppDelegate and MainViewController (even though one of those initiated the update)?
As always, I appreciate everyone's eyeballs on this as my quest for the ideal implementation continues. :)
Status Update #2
A comment from #Caleb helped me understand that an NSNotification-based setup would be a lot less unwieldy for this particular problem.
Thanks, all!
I don't see he need for a shared object here, much less a singleton. Do you really need to find the current Document at arbitrary times from many different objects? Seems more like you just have two objects (app delegate and view controller) that both need to know about the current Document. Notifications provide an easy way to manage that: whenever a switch happens, you can post a NSNotification that includes the new Document. Any objects that need to know about the current Document will have registered for the "document switch" notification, and when the notification arrives they can stash a pointer to the Document in an instance variable or property.
I do remember hearing that singletons are not meant to be destroyed
and recreated...
Well, you can have references inside of it, so you are not actually "destroying" the singleton, but the objects he points to. I tend to leave the App Delegate without application logic, so I normally put it somewhere else. In your case, since you need to access something from different places, it makes sense to have one. About the cluster, you can still have it, you just ask the singleton to access it and return the appropriate object like so:
Document *myDocument = [[MySingleton defaultManager] createObjectWithType:aType];
You gain some things out of this:
you can access your cluster from any place in your app
you decouple things, only one entity knows about your cluster.
Inside the Singleton you can have a reference to you AppDelegate and interact with it.
Inside the Singleton you can have a reference to the objects that are being used (Document A, Document B)
One more thing, I would advise putting the cluster access method as a class method (instead of an instance one).
I am creating one of my first Objective-C apps. I have a bunch of UIViews and Other views such as MapView and so forth.
In my Model I have a method called register that all views, well, register with. They are all put in a NSMutableArray in the model. Any time the model has updated data I run a for loop over the array of "views" and I would like all views no matter there type to implement a method called "update" that can be called from the model on each view.
Being that a view could be a UIView or of any other type I'm not really sure what the Objective-c way is of doing this is.
I'd really like to be able to do something like the following but I know this is not correct.
for(NSInteger i=0; i<[_views count]; i++)
{
NSObject *view = [_views objectAtIndex:i];
[view update:data];
}
Define a protocol:
#protocol IUpdateable <NSObject>
#required
-(void)update:(id)data;
#end
Then in your view class implement the protocol...
#interface SomeView : UIView <IUpdateable>
#end;
#implementation SomeView
-(void)update:(id)data
{
//Do something with data
}
#end;
Then you can call your methods in one fell swoop assuming your _views array contains a collection of IUpdateable views...
[_views makeObjectsPerformSelector:#selector(update:) withObject:someData];
Reference: NSArray, Working with Protocols
You are trying to do the same thing the Cocoa delegates do. Define a formal protocol with the update method, and make all your UIView classes (or any other classes that you want to be registerable with the model) adopt that protocol.
Define the protocol:
#protocol Updateable <NSObject>
#required
- (void) update: (id)data;
#end
Adopt the protocol:
#interface MyView : UIView <Updateable>
- (void) update: (id)data;
...
#end;
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.
So, I have a decent idea of what a delegate does, why use it, how to implement it etc. and I'm working on implementing it in one of my projects. The problem I'm trying to solve is to decouple my Controller objects from my Network Access class. In this context, the ideas get a little messy in my head.
I somehow intuitively feel that the NetworkAccessClass should be the delegate for a Controller object, because the NetworkAccessClass is acting as a helper for the Controller object. But it seems to work in a reverse fashion, because the following is apparently the right way to do it:
NetworkaccessClass.h
#protocol NetworkAccessDelegate
-(void) requestSucceded:(NSData *) data
-(void) requestFailed:(int) responseCode;
#end
#interface NetworkAccessClass : NSObject
{
id<NetworkAccessDelegate> networkDelegate;
}
#property(nonatomic, assign) id networkDelegate;
-(void) initWithDelegate:(id) delegate; //
#end
NetworkAccessClass.m
#implementation
#synthesize networkDelegate
-(void) initWithParams:(id) delegate
{
networkDelegate = delegate;
// Assign GET/POST vals, create request etc
[request startAsynchronous];
}
-(void) requestSucceded:(ASIHTTPRequest *) request
{
if([networkDelegate respondsToSelector:#selector(requestSucceded:)]) {
// Send the data to the controller object for it to use
...
}
}
-(void) requestFailed:(ASIHTTPRequest *) request
{
// Same as above. Send to request failed.
}
#end
And finally in my FirstViewController.h
#import "NetworkAccessClass.h"
#interface FirstViewController<NetworkAccessDelegate>
{
}
-(void) requestSucceded:(NSData *) data;
-(void) requestFailed:(int) responseCode;
#end
And the same in SecondViewController.h and so on.
Although this does decouple my Controllers from my Network class, I can't help feel it's wrong because the controllers in this case are acting as delegates or helper methods to the Network Class and not the other way round. Am I missing something basic? Or is this how it is?
Thanks,
Teja.
Delegates aren't "helper methods". Think of them as objects that get notified when something happens. (Although don't confuse them with "Notifications"--that's a different thing entirely.) In this case, your network class does it's stuff and then calls its delegate method on the View Controller that instantiated and fired, it to report the contents of that response to the view controller. The controller will then, presumably, update the view with the data that the network connector got. Classic delegate pattern, right there.