0

Title itself is enough for my question I guess. However I will explain further here, consider I have a two view controller A and B. A is base and it is pushing B, In one situation I want the A to be intimated from B when one button is clicked in View (B). Objective C is allowing to call directly A view if I have that instance. I think it is not a good practice to do that. How this case should be handled..

thanks for your suggestions.

Newbee
  • 3,231
  • 7
  • 42
  • 74

1 Answers1

2

IF by 'A intimated from B' you mean you want to invoke the A that was initially responsible for pushing B, you just go back to A using the 'back' button, or in code:

[self.navigationController popViewController animated:YES];

B doesn't need a pointer to A, the Navigation Controller has that, and B has a pointer to the Nav Controller because the Nav Controller sets B's navigationController property when it creates B.

If you need to set a property in A based on some action in B, you should use a delegate to do that.

In B, you make a property called delegate.

In A, when you create B, set it's delegate to A:

ViewControllerB* vcB = [[ViewControllerB alloc] init];
vcB.delegate = self;
[self.navigationController pushViewController:vcB];

Then in B you can call back to A via the delegate before the pop:

[self.delegate sendMessageWithValue:someValue];
[self.navigationController popViewController animated:YES];

If you want to be extra-cautious, you can enclose the message-passing with:

if ([self.delegate respondsToSelector:@selector(sendMessageWithValue:)]) { ... }

To make this work without B knowing anything about A, other than that it is the delegate, B should declare a delegate protocol in the header (above @interface)

@protocol BDelegateProtocol
- (void) sendMessageWithValue:(int)someValue;
@end

When you declare the delegate property in B's @interface, specify the protocol it is expected to follow:

@property (nonatomic, weak) id <BDelegateProtocol> delegate;

And in A's @interface header, advertise that you follow that protocol:

#import BViewController;

@interface AViewController:UIViewController <BDelegateProtocol>

This is the loose coupling you are after. B doesn't have to import A's header. It needs to know nothing about A other than that it conforms to B's protocol specification.

B does hold a pointer to A but it is a weak pointer. This is very important. If the delegate property was strong, B would increase the retain count of it's delegate by 1. If the delegate also holds a strong pointer to B, then neither of them can ever get deallocated. B will always have a retain count of at least 1 while A exists, and likewise A will always have a retain count of 1 while B exists: neither can be destroyed.

In this particular case that may not happen - A doesn't need to retain B as it's Nav Controller does - but it is a situation that can arise frequently as a delegate is very often the object that creates and owns the delegator. See "Use Weak References to Avoid Retain Cycles" in Apple's Practical Memory Management

foundry
  • 31,615
  • 9
  • 90
  • 125
  • I want a flag to be set in View A if that particular button is clicked, and I don't want to pop B for that case. – Newbee Jan 17 '13 at 09:37
  • Is this how the cyclic reference is handled in Objective C with Delegate? – Newbee Jan 17 '13 at 09:47
  • Thanks for your answer.. One doubts.. Why do we need to create weak property in B, why not strong. – Newbee Jan 17 '13 at 09:56
  • 1
    @Newbee, see "Use Weak References to Avoid Retain Cycles" in Apple's [_Practical Memory Management_](https://developer.apple.com/library/mac/#DOCUMENTATION/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html) – foundry Jan 17 '13 at 10:13