Two Independent Delegate Methods in a Class - iphone

I have two independent delegate methods in a class.
- (void)delegateMethod1:(id)data {
self.data = data;
}
- (void)delegateMethod2 {
[someClass sendData:self.data];
}
Now, this works fine sometimes but the other times, delegateMethod2 gets called before delegateMethod1.
I need to know how to manage this elegantly so that the line: [someClass sendData:self.data]; gets called only when both delegateMethod1 and delegateMethod2 have been called.
I know I can do it by using a variable to set to something on each delegate call but there has to be an elegant way to do this.
Any help?

Remembering which delegate has been called seems the easiest and cleanest solution to me.
But you can make it symmetric by moving the check to a separate method, so that
is does not matter which delegate is called first:
- (void)checkIfDataCanBeSent {
if (self.method1called && self.method2called) {
[someClass sendData:self.data];
}
}
- (void)delegateMethod1:(id)data {
self.method1called = YES;
// ...
[self checkIfDataCanBeSent];
}
- (void)delegateMethod2 {
self.method2called = YES;
// ...
[self checkIfDataCanBeSent];
}
(I have assumed that all delegate methods are called on the main thread, otherwise
one would have to add some synchronization.)

I believe, using a indicative variable to be the most elegant way to get over this. But this variable has to be kept in the delegate caller object.
Pseudo-type explanation
#interface DelegateCaller
{
BOOL hasCalled1stMethod;
}
#property(nonatomic,weak) id delegate;
#end
#implementation DelegateCaller
-(void)in_some_process_1
{
[self.delegate delegateMethod1]; //call
hasCalled1stMethod = YES; //set indicator
}
-(void)in_some_process_2
{
if(hasCalled1stMethod)
{
[self.delegate delegateMethod2]; //call
hasCalled1stMethod = NO; //reset indicator for reuse, if required.
}
}
#end
This way you'll not have to maintain any variable in the delegate itself, because the regulation of calling is maintained in the caller-object itself.
Another case:
If the delegateMethod1 is called from some object1 and the delegateMethod2 is called from some other object2, then again the indicative variable method is the most elegant way (in this limited scenario)
Pseudo-type explanation:
#interface ClassDelegateObject //aka the callee
{
BOOL hasCalledMethod1;
}
#end
#implementation ClassDelegateObject
-(void)delegateMethod1:(NSData*)data
{
self.data = data;
hasCalledMethod1 = YES; //set the indicator.
}
-(void)delegateMethod2
{
//here relying on the self.data!=nil will not be fruitful
//in case the self.data is not nil and hold some previous garbage data then
//this logic will fail.
if(hasCalledMethod1)
{
[someClass sendData:self.data];
hasCalledMethod1 = NO; //reset the variable for reuse if required.
}
}
#end

I would suggest that you rethink how the code works. Maybe you can check if there is no data and if so send it once it is ready:
- (void)delegateMethod1:(id)data {
self.data = data;
if (self.dataShouldBeSentWhenReady) {
[self sendData];
}
}
- (void)delegateMethod2 {
if (self.data) {
[self sendData];
} else {
[self setDataShouldBeSentWhenReady:YES];
}
}
- (void)sendData {
[self setDataShouldBeSentWhenReady:NO];
[someClass sendData:self.data];
}

Related

Efficient way to count view visits in iOS app

I have an iOS app with about 50 views. I want to perform some operation after every 5th screen that the user visits. I know I can create a sort of global counter variable and update that on viewDidLoad of each view, and if count is 5, then perform that operation, and reset that counter variable. Is there a better, more efficient way of doing this? Also looking ahead, if I require to alter something, I would rather do it in a single file than all of my views. Would really appreciate some inputs on this.
I would create a singleton class to keep track of your counter logic, create a base class for all of your view controllers and then make your call to the counter singleton in the viewDidLoad of your base class.
I think something like this would work for you:
#interface ViewCountManager()
#property(nonatomic) NSInteger viewCount;
#end
#implementation ViewCountManager
#define kOperateOnCount 5
+(ViewCountManager *)viewCountManager
{
static ViewCountManager *viewCountManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
viewCountManager = [[self alloc] init];
});
return viewCountManager;
}
-(BOOL)shouldPerformOperation
{
BOOL retValue = NO;
if( self.viewCount == kOperateOnCount - 1 )
{
retValue = YES;
self.viewCount = 0;
}
else
{
self.viewCount++;
}
return retValue;
}
#end
#implementation CountedViewController
-(void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad:animated];
BOOL shouldPerform = [[ViewCountManager viewCountManager] shouldPerformOperation];
[self performOperation];
}
#end

SAFELY_RELEASE in ViewDidUnLoad

is there any difference between the two methods?
```
// MACRO FUNCTION
#define SAFELY_RELEASE(__POINTER) { [__POINTER release]; __POINTER = nil; }
// C FUNCTION
void SAFELY_RELEASE(id __POINTER) {
[__POINTER release]; __POINTER = nil;
}
```
Yes. The function won't do what you expect it to, because the pointer will have been passed into it by value, rather than by reference.
Imagine this:
- (void)method {
id object = [[NSObject alloc] init];
SAFELY_RELEASE( object );
}
SAFELY_RELEASE gets object. It can send it messages, but setting it to nil will not change its value in method.
An equivalent function would be:
void SAFELY_RELEASE(id *__POINTER) {
[*__POINTER release]; *__POINTER = nil;
}
Then you'd use it by using:
SAFELY_RELEASE( &object );
The macro has another downside, though: Xcode's refactoring tools will probably not be able to change the parameter inside. For instance:
#interface Foo {
NSObject *var;
}
#implementation Foo
- (id)init {
if (( self = [super init] )) {
var = [[NSObject alloc] init];
}
return self;
}
- (void)dealloc {
SAFELY_RELEASE(var);
[super dealloc];
}
If you try to rename var using the refactor tool, you'll probably find that it won't be able to rename the var in dealloc.
Really, unless you have a really good reason to do this you should be using ARC.
void SAFELY_RELEASE(id __POINTER) is guaranted to __POINTER be an releasable object.
Both of them is wrong, because __POINTER = nil; will have no effects. You should nil it in object (controller)
I was using one of these macros, then I cam across this post.
Makes sense that you don't want to set to nil while in development as you want it to crash on a dealloc reference and not sending it to nil.

UIPageControl and delay in appearing

How do I make an instance of UIPageControl appear immediately? (I have set defersCurrentPageDisplay to NO.)
I have an instance of UIPageControl which is configured (number of pages, current page and then updated) when my view appears. However there is a short, fixed delay before it appears to the user. I'd like it to appear right away.
Otherwise it's working fine.
The problem is I'm performing a lengthy background process and I've inadvertently and ultimately called updateCurrentPageDisplay etc. from this secondary thread. UIKit is not thread-safe and blocks this call until it can move it to the main thread, hence the delay.
To solve this, I've subclassed UIPageControl creating "wrapper" methods that push calls to super onto the main thread. I can then safely forget about this every time I need to speak with my page controls.
For example:
- (void) updateCurrentPageDisplay
{
#synchronized(self)
{
if ([UIDevice currentDeviceSupportsGrandCentralDispatch] == YES)
{
dispatch_async(dispatch_get_main_queue(), ^{
[super updateCurrentPageDisplay];
});
}
else
{
[super performSelectorOnMainThread:#selector(updateCurrentPageDisplay)
withObject:nil
waitUntilDone:NO];
}
}
}
I have fixed the delay issue by adding the UIPageViewController delegate's willTransitionToViewControllers and setting the pageController's index there:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
for (MyContentPageViewController *contentController in pendingViewControllers) {
if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
NSUInteger newIndex = contentController.pageIndex;
[self.pageControl setCurrentPage:newIndex];
}
}
Then, to avoid bugs in cases where swipe is not completed, add the following delegate method:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
if(finished){
for (MyContentPageViewController *contentController in previousViewControllers) {
if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
NSUInteger currentIndex = MIN(MAX(0, contentController.pageIndex), _allPages.count- 1);
[self.pageControl setCurrentPage:currentIndex];
}
}
} else {
for (MyContentPageViewController *contentController in previousViewControllers) {
if ([contentController isKindOfClass:[MyContentPageViewController class]]) {
NSUInteger currentIndex = MIN(MAX(0, contentController.pageIndex), _allPages.count);
[self.pageControl setCurrentPage:currentIndex];
}
}
}
}

Wait for MKReverseGeocoder to provide address

Is there a way to wait for geocoder to invoke didFailWithError or didFindPlaceMark?
My problem is that i have to call a method that receives coordinate and returns placemark holding the address. But when i call [myGeocoder start] code continues and i get an empty placemark.
My code is:
- (MKPlasemark*) getAddress:(CLLocationCoordinate2D) coordinate
{
[self startGeocoder:coordinate];
return self.foundPlasemark;
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFindPlacemark:(MKPlaseMark*)plasemark
{
self.foundPlasemark=plasemark;
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFailWithError:(NSError*)error
{
self.foundPlasemark=nil;
}
I tryed to perform sleep() whyle one of the following methods invoked, but it didn't work.
I think you are going about it the wrong way, there is no reason to block, what you have to do is have that method return void, and in the class that is handling the geocoding, define a protocol that has a method say -(void)didReceivePlacemark:(id)placemark, placemark can be nil or some placemark, and it is called when the geocoder returns. You also make a delegate property for your class so anyone can subscribe to the protocol... Then in the calling class subscribe to the protocol and implement the method...heres a bit more on protocols
Hope that helps
Here is an example:
So the interface of your class that does the geocoding will look something like this
#protocol GeocoderControllerDelegate
-(void)didFindGeoTag:(id)sender; // this is the call back method
#end
#interface GeocoderController : NSObject {
id delegate;
}
#property(assign) id <GeocoderControllerDelegate> delegate;
Then in the implementation you would see something like this
- (void) getAddress:(CLLocationCoordinate2D) coordinate
{
[self startGeocoder:coordinate];
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFindPlacemark:(MKPlaseMark*)plasemark
{
[delegate didFindGeoTag:plasemark];
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFailWithError:(NSError*)error
{
[delegate didFindGeoTag:nil]
}
In the calling class, all you have to set is the delegate property of the GeocoderClass, and implement the protocol, the implementation might look somethign like
-(void)findMethod
{
GeocoderController *c=...
[c setDelegate:self];
[c findAddress];
//at this point u stop doing anything and just wait for the call back to occur
//this is much preferable than blocking
}
-(void)didFindGeoTag:(id)sender
{
if(sender)
{
//do something with placemark
}
else
{
//geocoding failed
}
}

Searching for the Right Pattern (iPhone/Objective C)

EDIT: It was suggested to me that I implement the strategy pattern (http://en.wikipedia.org/wiki/Strategy_pattern), which I think I would do as several objects that implement a delegate protocol in Objective-C. This accomplishes the encapsulation I want while still allowing me to have a generic view controller in memory.
I have a class called DetailViewController that displays information about various types of data - waypoints, trails, maps, photos.
Right now, this class is 1400 lines long and it has some messy switch statements. For example:
- (void) changeMiniView:(id)sender {
if (self.track) {
[self changeTrackMiniView:[sender selectedSegmentIndex]];
} else if (self.waypoint) {
[self changeWaypointMiniView:[sender selectedSegmentIndex]];
} else if (self.photo) {
[self changePhotoMiniView:[sender selectedSegmentIndex]];
} else if (self.map) {
[self changeMapMiniView:[sender selectedSegmentIndex]];
}
}
This would be a lot neater if I made subclasses of DetailViewController, but my conundrum is I would like to keep the viewController in memory and just change certain elements, so I can have crisp transitions, particularly on 3G phones.
I feel like if I want my code to be neat, I have to take a performance hit.
Have the current view in a field in your object (rather than one field for every type of miniview you have), and implement changeMiniView for each of them.
Then your method would look like:
- (void) changeMiniView: (id)sender {
[self.currentMiniView changeMiniView: [sender selectedSegmentIndex]];
}
How about using selector?
- (void)viewDidLoad {
if (self.track) {
sel = #selector(changeTrackMiniView:);
} else if (self.waypoint) {
sel = #selector(changeWaypointMiniView:);
} else if (self.photo) {
sel = #selector(changePhotoMiniView:);
} else if (self.map) {
sel = #selector(changeMapMiniView:);
}
}
- (void)changeTrackMiniView:(id)sender {
....
}
- (void)changeMiniView:(id)sender {
[self performSelector:sel withObject:sender];
}