Delegates query in Objective - C - objective-c

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.

Related

Can anyone please help me out? iOS How Datasource methods are implemented? and How do they work?

I am trying to implements my own Datasource methods.Not getting how can we implements.
Datasources and delegates are both implemented using protocols. The difference between the two is that the delegate controls user interaction and the datasource controls data.
This means that your typical delegate method will be called from something like a button click and your datasource method will be called during initialization or refresh of the control. It also means that delegates are more likely to have void methods and data source methods will most likely define a return type.
If you take an example that has a view controller and your custom control, then you would do something like this to setup your datasource protocol.
CustomControl.h:
#protocol CustomControlDatasource <NSObject>
- (NSInteger)NumberOfThingsInControl;
#end
#interface CustomControl : NSObject
#property (nonatomic, weak) id <CustomControlDatasource> delegate;
#end
You could call datasource methods from your init or refresh method and use the result to configure the control however you'd like (don't forget to synthesize the delegate property).
CustomControl.m:
#synthesize datasource = _datasource;
...
-(void)refresh {
NSInteger numOfThings = [self.datasource NumberOfThings];
// Use the result to update the control
...
}
The class that implements the datasource needs to conform to it and implement the datasource method.
MyViewController.h:
#interface MyViewController : UIViewController <CustomControlDelegate> {
CustomControl *coolControl;
}
#end
MyViewController.h:
- (void)viewDidLoad {
[super viewDidLoad];
coolControl = [[CustomControl alloc] init];
[coolControl setDatasource:self];
[coolControl refresh];
}
- (NSInteger)NumberOfThingsInControl {
return 3;
}
I hope this clears things up a bit. protocols are an awesome way to have objects communicate.
You can read more in the documentation:
Working with Protocols
Delegates and Data Sources

Sending a message to an instance method from inside a block

I am relatively new to Cocoa programming. Basically, I want to send a message within a method in my Document class to an intense of a class (that inherits from NSView) that I have initialised as a property in the #interface of the Document class.
Here is the simplified version:
///////////////////////////KOZDocument.h///////////////////////////
#import <Cocoa/Cocoa.h>
#import "KOZOtherClass.h"
#interface KOZDocument : NSDocument
#property (assign) IBOutlet KOZOtherClass *otherClassInstance; //this would be connected to the relevant CustomView in the IB
#end
///////////////////////////KOZDocument.m///////////////////////////
#import "KOZDocument.h"
#implementation KOZDocument
- (id)init
{
self = [super init];
if (self) {
// I want to send a message to otherClassInstance from some method e.g. init
NSLog(#"INITIALISING");
[[self otherClassInstance] printMessage];// this is the message I want to work but which doesn't (even though i don't any errors)
//sending the message to a locally initiated instance works but I don't want to use a local instance because i want to connect it to a CustomView in IB
KOZOtherClass *otherClassLocalInstance = [[KOZOtherClass alloc] init];
[otherClassLocalInstance printMessage];
}
return self;
}
//.….
///////////////////////////KOZOtherClass.h///////////////////////////
#import <Foundation/Foundation.h>
#interface KOZOtherClass : NSView
- (void) printMessage;
#end
///////////////////////////KOZOtherClass.m///////////////////////////
#import "KOZOtherClass.h"
#implementation KOZOtherClass
- (void) printMessage{
NSLog(#"This method can be called!!");
}
#end
/////////////////////////////////////////////////////////////////////
The same methodology works for all the native Cocoa objects but not for mine.
Can anyone tell me what I'm doing wrong?
Here is the context of why i want to do this:
I am building an app that plays a video using the AVFoundation. I have an animation I want to trigger in an NSView when the playback reaches a particular part in the video (e.g. after 2 seconds). I am adapting Apple's AVSimplePlayer and using the time observer to get the position of the playhead. The time observer executes the code inside a block for every given time interval. In this block I want to send a message to my animation view to trigger the animation when the time is more that 5 seconds for example.
In -init of your objects the Interface Builder connections are not set yet, the loading mechanism can't set those before your object is initialized.
Instead you want to overwrite the -awakeFromNib method like so:
- (void)awakeFromNib {
[[self otherClassInstance] printMessage];
}
-awakeFromNib is guaranteed to be called after the connections have been made. Depending on the exact implementation you may also need to guard against that code being executed twice, for example by having a boolean instance variable didWake that you check/set in that method.

Class Cluster as a Singleton?

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).

is this a good use of the copy method for an NSArray?

you have a class or ViewController using model/service class like so:
#interface MainViewController : UIViewController <TweetServiceDelegate> {
NSArray *_tweets;
}
#property (nonatomic, strong) TweetService *tweetService;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.twitterService queryForLatestTweets];
}
// delegate methods the tweetservice calls back after async getting data
- (void)querySucceededWithTweets:(NSArray *)tweets {
_tweets = [tweets copy];
}
#end
The reason I ask because the Service has a weak reference to the delegate, which is the ViewController.
So I know with ARC you don't want 2 things that use each other to both have a strong reference, so if it's weak but the ViewController retains the NSArray, then the Service wouldn't be collected once it went out of scope, assuming the service did go out of scope but the ViewController didn't
#interface TweetService
#property (nonatomic, weak) id<TweetServiceDelegate> delegate;
#end
#implementation TweetService
- (void)queryForLatestTweets {
// do the query with AFNetworking, when succeed block fires, call the delegate
[self.delegate querySucceededWithTweets:arrayOfTweets];
}
#end
I would say this is rather the recommended way of doing this sort of things. The service is held strongly by the controller that needs it, but the service holds the controller only weakly as a delegate because it does not need to know what its delegate is -- or even if it exists -- to function.
When the service returns something through delegate methods back to its delegate, the delegate should claim ownership of the data. The preferred way is to copy, since the delegate does not know anything about the return value's lifecycle. copy makes a new instance that can be think as a "snapshot" of the data. Working on this "snapshot" guarantees that your data are not modified when you don't want them to. This effectively decouples the service and the delegate.
A side note: Your self._tweets won't work because _tweets is an instance variable, but the dot syntax expects a property. _tweets = [tweets copy]; would be correct.
I will say YES it is good to use because...
if you are not copying that array just simply assign _tweet = tweet array.
then if you are doing change in any one of the array it will affect to other array..
so Yes i will suggest you to use COPY method such time...
Thanks.

Update UILabel text from another class in Objective-C

I have a method implemented in the ViewCotroller class to set the message to a UILable in that class.
-(void)setAuthenticationMessage:(NSString *)message{
//lblStatus is the UILabel
lblStatus.text = message;
}
I'm accessing this method from another class to set the message. Though code executes correctly this message didn't update. I tried it by executing this method in a different thread. But that was also unsuccessful. Can anyone help me to figure out the issue?
What are lblStatus's memory management properties? Your naming convention alone leads me to believe that it is something to do with this. Usually you refer to instance variables as:
_lblStatus or self.lblStatus
use #protocol & delegates to access another class refer this link example example2
Use the delegate design pattern (google it). Example:
//In the updating class .h
#protocol LabelChangerDelegate <NSObject>
-(void)handleLabelChangeMessage;
#end
#property (assign, nonatomic) id <LabelChangerDelegate> delegate;
//In the updating class .m
-(void)changeLabelInOtherClass{
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(handleLabelChangeMessage)]) {
[self.delegate performSelector:#selector(handleLabelChangeMessage)];
}
} else {
NSLog(#"Delgate doesn't implement handleLabelChangeMessage");
}
//In the view controller .h
<LabelChangerDelegate>
-(void)viewDidLoad{
//set the delegate to self
}
//In the view controller .m
-(void)handleLabelChangeMessage{
self.label.text=#"I changed through delegation";
}
Another option is to use NSNotificationCenter