IOS, UIView, Detect Hidden State Change in Subview - ios

Is there anyway to detect a hidden state change (or other change) in a sub view in a UIView (not UIViewController). Would like to detect this async somehow.
There are reasons for my madness.

You can use KVO (key value observing) to detect a change to the value of the property hidden.
Add your observer (self in this example) in the following way:
UIView* viewToObserve = [self getViewToObserve]; // implement getViewToObserve
[viewToObserve addObserver:self forKeyPath:#"hidden" options:0 context:NULL];
Now add the following method to your observer class:
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
UIView* viewToObserve = [self getViewToObserve];
if (object == viewToObserve)
{
if ([keyPath isEqualToString:#"hidden"])
{
// react to state change
}
}
}
The observer method will be invoked whenever the hiddenproperty changes its value. If I am not mistaken, the method will be invoked synchronously in the context of the thread that makes the change to the property. If you need asynchronous notification you can add that yourself, for instance by using one of the NSObject methods performSelector:withObject:afterDelay: or performSelector:onThread:withObject:waitUntilDone:.
BTW: You don't need the checks in the observer method, obviously, if you only observe a single object and/or property. I left the checks in for illustration purposes. I also recommend reading Apple's documentation on KVO and KVC (key value coding) to understand what's going on here.
The runtime happily continues notifying your observer even if the observer is deallocated - resulting in an application crash! So don't forget to remove the observer before it is de-allocated, at the latest this should happen in the observer's dealloc:
- (void) dealloc
{
UIView* viewToObserve = [self getViewToObserve];
[viewToObserve removeObserver:self forKeyPath:#"hidden"];
[super dealloc];
}

You can override the property in the UIView subclass and do anything in didSet
class MyView: UIView {
override var isHidden: Bool {
didSet {
//do something
}
}
}

Related

Crash - UITableViewCell subclass KVO'ing UITableView.panGestureRecogonizer.state

Situation:
I've subclassed UITableViewCell because I need to add custom action buttons on either side of the UITableViewCell. There are certain situations where I need to set the UITableView back to normal (hide the custom action buttons). e.g. When the user scrolls upwards in the UITableView. To do this I am adding my custom UITableViewCell as an observer of the containing UITableView's UIPangestureRecognizer's state.
Problem:
When popping the UIViewController that contains the UITableView and custom UITableViewCells I receive the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7b21b920 of
class UIScrollViewPanGestureRecognizer was deallocated while key value
observers were still registered with it. Current observation info:
( Context: 0xb83618, Property: 0x7b3e13b0>
Context: 0xb83618,
Property: 0x7b3e13b0>
Context: 0xb83618, Property: 0x7b3e13b0> Context: 0xb83618, Property: 0x7b3e13b0> )'
Which is obviously saying that the UIPanGestureRecognizer is being deallocated before the custom UITableViewCell's are.
Question:
Where should I remove the custom UITableViewCell as an observer of the UITableView's UIPanGestureRecognizer so I don't encounter this exception?
Code: (I hope this isn't too much code to comb through. I apologize if it is.)
CustomUITableViewCell.m
#pragma mark - Setter Methods
- (void)setContainingTableView:(UITableView *)containingTableView
{
if (self.isObservingContainingTableViewPanGestureRecognizer)
{
self.observingContainingTableViewPanGestureRecognizer = NO;
[_containingTableView.panGestureRecognizer removeObserver:self forKeyPath:kUITableViewPanGestureRecognizerStateKeyPath];
}
_containingTableView = containingTableView;
if (containingTableView)
{
self.observingContainingTableViewPanGestureRecognizer = YES;
[containingTableView.panGestureRecognizer addObserver:self forKeyPath:kUITableViewPanGestureRecognizerStateKeyPath options:0 context:UITableViewPanGestureRecogonizerContext];
}
}
#pragma mark -
#pragma mark - Overrides
- (void)didMoveToSuperview
{
[super didMoveToSuperview];
self.containingTableView = nil;
UIView * view = self.superview;
while (view)
{
if ([view isKindOfClass:[UITableView class]])
{
self.containingTableView = (UITableView *)view;
break;
}
view = view.superview;
}
}
- (void)dealloc
{
self.containingTableView = nil;
}
#pragma mark -
#pragma mark - Key Value Observing
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == UITableViewPanGestureRecogonizerContext)
{
if ([keyPath isEqual:kUITableViewPanGestureRecognizerStateKeyPath])
{
UIPanGestureRecognizer * panGestureRecognizer = (UIPanGestureRecognizer *)object;
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint velocity = [panGestureRecognizer velocityInView:self.contentCellView];
if (fabs(velocity.y) >= fabs(velocity.x))
{
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
}
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark -
As always, any help is greatly appreciated! Also, if anyone needs any more information please let me know.
EDIT:
Oddly enough, the custom UITableViewCell's dealloc method is called and the custom UITableViewCell is removed as an observer before I the exception is thrown.
It turns out that I needed to keep a reference to the UITableView's UIPanGestureRecognizer. More than likely I'll end up subclassing UITableView to eliminate some of the complications.
UITableView is subclass of UIScrollView. If you only want to detect when user is scrolling it you can use scrollview delegate method:
(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
I think you should pass weak reference of table view to cell (as delegate) in cellForRowAtIndexPath rather than looking for the tableview in didMoveToSuperview. Overall, I don't think it's a good idea to have table view's gesture observer in cell. However if you really want it, make sure you register/unregister properly.
Also make sure isObservingContainingTableViewPanGestureRecognizer flag's initial value is right when the cell gets reused.

How to do some stuff in viewDidAppear only once?

I want to check the pasteboard and show an alert if it contains specific values when the view appears. I can place the code into viewDidLoad to ensure it's only invoked once, but the problem is that the alert view shows too quickly. I know I can set a timer to defer the alert's appearance, but it's not a good work-around I think.
I checked the question iOS 7 - Difference between viewDidLoad and viewDidAppear and found that there is one step for checking whether the view exists. So I wonder if there's any api for doing this?
Update: The "only once" means the lifetime of the view controller instance.
There is a standard, built-in method you can use for this.
Objective-C:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([self isBeingPresented] || [self isMovingToParentViewController]) {
// Perform an action that will only be done once
}
}
Swift 3:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isBeingPresented || self.isMovingToParentViewController {
// Perform an action that will only be done once
}
}
The call to isBeingPresented is true when a view controller is first being shown as a result of being shown modally. isMovingToParentViewController is true when a view controller is first being pushed onto the navigation stack. One of the two will be true the first time the view controller appears.
No need to deal with BOOL ivars or any other trick to track the first call.
rmaddy's answers is really good but it does not solve the problem when the view controller is the root view controller of a navigation controller and all other containers that do not pass these flags to its child view controller.
So such situations i find best to use a flag and consume it later on.
#interface SomeViewController()
{
BOOL isfirstAppeareanceExecutionDone;
}
#end
#implementation SomeViewController
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(isfirstAppeareanceExecutionDone == NO) {
// Do your stuff
isfirstAppeareanceExecutionDone = YES;
}
}
#end
If I understand your question correctly, you can simply set a BOOL variable to recognize that viewDidAppear has already been called, ex:
- (void)viewDidAppear {
if (!self.viewHasBeenSet) { // <-- BOOL default value equals NO
// Perform whatever code you'd like to perform
// the first time viewDidAppear is called
self.viewHasBeenSet = YES;
}
}
This solution will call viewDidAppear only once throughout the life cycle of the app even if you create the multiple object of the view controller this won't be called after one time. Please refer to the rmaddy's answer above
You can either perform selector in viewDidLoad or you can use dispatch_once_t in you viewDidAppear. If you find a better solution then please do share with me. This is how I do the stuff.
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:2.0];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static dispatch_once_t once;
dispatch_once(&once, ^{
//your stuff
[self myMethod];
});
}
By reading other comments (and based on #rmaddy 's answer), I know this is not what OP asked for, but for those who come here because of title of the question:
extension UIViewController {
var isPresentingForFirstTime: Bool {
return isBeingPresented() || isMovingToParentViewController()
}
}
UPDATE
You should use this method in viewDidAppear and viewWillAppear. (thanks to #rmaddy)
UPDATE 2
This method only works with modally presented view controllers and pushed view controllers. it's not working with a childViewController. using didMoveToParentViewController would be better with childViewControllers.
You shouldn't have issues in nested view controllers with this check
extension UIViewController {
var isPresentingForFirstTime: Bool {
if let parent = parent {
return parent.isPresentingForFirstTime
}
return isBeingPresented || isMovingFromParent
}
}
Try to set a BOOL value, when the situation happens call it.
#interface AViewController : UIViewController
#property(nonatomic) BOOL doSomeStuff;
#end
#implementation AViewController
- (void) viewWillAppear:(BOOL)animated
{
if(doSomeStuff)
{
[self doSomeStuff];
doSomeStuff = NO;
}
}
in somewhere you init AViewController instance:
AddEventViewController *ad = [AddEventViewController new];
ad.doSomeStuff = YES;
Not sure why you do this in ViewDidAppear? But if you want doSomeStuff is private and soSomeStuff was called only once, here is another solution by notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSomeStuff) name:#"do_some_stuff" object:nil];
- (void) doSomeStuff
{}
Then post when somewhere:
[[NSNotificationCenter defaultCenter] postNotificationName:#"do_some_stuff" object:nil];
swift 5
I've tried isBeingPresented() or isMovingToParent.
But It doesn't work.
So I tried below code. and It's work for me!
override func viewDidAppear(_ animated: Bool) {
if (self.isViewLoaded) {
// run only once
}
}
You can use this function in ViewDidLoad method
performSelector:withObject:afterDelay:
it will call that function after delay. so you don't have to use any custom timer object.
and For once you can use
dispatch_once DCD block.Just performSelector in the dispatch_once block it will call performSelector only once when ViewDidLoad is called
Hope it helps

uitextfield rightView visible when user typed at least one char in the field

I was wondering if there is any way I can make the right view of an UITextField only be visible when there is at least one character inside, because by setting UITextFieldViewModeWhileEditing will show it once I focus on the field, not when I start typing.
I could only come up with implementing the UITextFieldDelegate and doing it on one of the methods that is triggered when the user is typing. The only issue here is that I change the delegate of the text field to something else once I create a text field and add it to the view. That is because I made a custom textfield by subclassing UITextField and I init it in various places, and in those various places I assign it's delegate to the current place it's initiated.
Here's a better idea. UITextField posts a change notification. Your subclass can observe itself this way:
// in RSSUITextField.m
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(textFieldChanged:)
name:UITextFieldTextDidChangeNotification
object:self];
Then implement textFieldChanged: and change your rightView state in there. This answer is superior to the other I left, but I won't remove that one since that works too, and is a useful technique for cases where the control doesn't post notifications about a state change we care about.
Since each instance of the RSSUITextField will observe itself with the NSNotificationCenter, each is responsible to remove itself as an observer when it no longer matters. The latest possible time to do this is on dealloc...
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
This answer works, but there's a better answer for your particular case. See my other answer... text field posts NSNotification when the text changes....
KVO would be ideal, but the UIKit doesn't promise KVO compliance. The more abstract problem statement is that you want one object to know something about the text field's state that can only be known by the delegate, but you sometimes want some other object to be the delegate.
The only idea I have that doesn't break any rules is to have the subclass be a proxy for the real delegate, like so...
// in RSSUITextField.m
#interface RSSUITextField () <UITextFieldDelegate>
// I will be my own delegate, but I need to respect the real one
#property (weak, nonatomic) id<UITextFieldDelegate>proxyDelegate;
#end
In the designated init...
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.delegate = self;
}
return self;
}
I am my own delegate, so when the caller of this class wants to get/set the delegate, I need to fool him...
- (id<UITextFieldDelegate>)delegate {
return self.proxyDelegate;
}
- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
self.proxyDelegate = delegate;
}
Now the important part (and then sad part). Important part: we're now in the position to know about our state as a delegate and still respect the caller's idea of the delegate...
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// show or change my right view
if ([self.proxyDelegate respondsToSelector:#selector(textFieldDidBeginEditing:)]) {
[self.proxyDelegate textFieldDidBeginEditing:textField];
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
// hide or change my right view
if ([self.proxyDelegate respondsToSelector:#selector(textFieldDidBeginEditing:)]) {
[self.proxyDelegate textFieldDidBeginEditing:textField];
}
}
The sad part: We broke it, so we bought it. In order to fully respect the delegate, we have to pass on all delegate messages. This isn't a disaster, because there are only five more of them. They will all take exactly this form:
// I only added this one as an example, but do this with all five others
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([self.proxyDelegate respondsToSelector:#selector(textFieldShouldReturn:)]) {
return [self.proxyDelegate textFieldShouldReturn:textField];
} else {
return YES; // the default from the docs
}
}

Update Text Label From Another View

I have an NSTimer that runs every 10 seconds and is kicked off from LandingController.m. It continues to run as you go to other views in the application. I want to be able to (when a certain condition is met within that timer) update a label field from another view GuardMenu.m The label I want to update is called CurrentZone.text and I want to update it from value "N" to value "Y."
Here's my timer on LandingController.m
self.messageTimer = [NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(checkForMessages)
userInfo:nil
repeats:YES];
Which calls this on LandingController.m
- (void)checkForMessages
{
if ( //some condition here ){
//update CurrentZone.text label in GuardMenu view and set equal to "Y"
} else {
//no need to update label in GuardMenu as it's currently equal to "N"
}
}
First create a NSNotification in your init method of GuardMenu class
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"TextChangeNotification" object:nil];
}
return self;
}
Then implement the notification's selector, this is where you will be changing your CurrentZone label text.
- (void)receiveNotification:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"TextChangeNotification"]) {
NSLog (#"Change you label here");
self.lblCurrentZone.text = #"Y";
}
}
Now in your LandingViewController.m -viewDidLoad Method
Start the timer.
self->msgTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(checkForMessages) userInfo:nil repeats:YES];
Now implement the #selector for the NSTimer, this is where you will be sending the notification back to the GuardMenu class
- (void)checkForMessages {
NSString *strText = #"test";
if ([strText isEqualToString:#"test"]){
[[NSNotificationCenter defaultCenter] postNotificationName:#"TextChangeNotification" object:nil];
}
else {
}
}
NOTE: the NotificationName should be the same.
Sample Project Code Dropbox Link
You can use the prepareForSegue method to pass objects between view controllers in the storyboard. For example, to pass a string from the GreyViewController to the OrangeViewController, in GreyViewController.m you have:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
OrangeViewController *orange = [segue destinationViewController];
orange.self.orangeString = #"text for orangeView";
}
Then in the viewDidLoad of the other view controller, in the OrangeViewController.m, you can set the text of the label by doing the following:
self.orangeLabel.text = self.orangeString;
Maybe you should describe which error you're getting. Is your checkForMessages method (not) firing? Use an NSLog() message to check. Otherwise, check if the UILabel you want to change is actually loaded into memory (i.e. is not nil). Please also let us know if the currentZone.text is part of the view hierarchy of the LandingController or of another view controller.
You can make use of notifications.
In GuardMenu class init register for custom notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"MessageChangeNotification"
object:nil];
In LandingController->checkForMessages method post the notification when condition is satisfied.
[[NSNotificationCenter defaultCenter] postNotificationName:#"MessageChangeNotification"
object:nil];
In GuardMenu class implement the notification callback selector
- (void) receiveNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"MessageChangeNotification"]) {
NSLog (#"Successfully received the notification");
//Change the label text here..
}
}
Hope it helps!
Amar.
Make sure that the label you are trying to edit is declared as a property in the appropriate view and properly synthesised. Also make sure it is connected in Interface Builder.
In GuardMenu.h
#property (strong, nonatomic) IBOutlet UILabel *CurrentZone;
Also, in LandingController.h, import GuardMenu.h:
#import "GuardMenu.h"
You will now be able to access the label and its text property from LandingController.h using
-(void)checkForMessages
{
GuardMenu *guardMenu = [[GuardMenu alloc]init];
if (/* some condition here */) {
//update CurrentZone.text label in GuardMenu view and set equal to "Y"
guardMenu.CurrentZone.text = #"Y";
} else {
//no need to update label in GuardMenu as it's currently equal to "N"
}
}
For this you should use KVO(Key Value Observing). There are lot of ways to pass notifications, but KVO is potentially much simpler. I suspect that Notification is used more often because you can do a ‘chain of responsibility’ for an event as opposed to just assigning an observer. However, just having an observer in a controller that can watch a particular property in another object and get notified of changes is a powerful and simple way to solve a whole class of problems.
Firstly set a public property in LandingController like "lablelText" .
Then add the observer once, when you create the LandingController view. Once you've added the observer, the observeValueForKeyPath:ofObject:change:context: method will be executed in GuardMenu, so you can do the update to the GuardMenu UI from there. You shouldn't need to do anything every time GuardMenu is about to appear.
In GuardMenu, you should probably create LandingController just before you are going to push LandingController onto the controller stack, presumably in the event handler for some action the user took. Immediately after you create LandingController, add the observer in GuardMenu with the correct NSKeyValueObservingOption value.
If you just want to be notified whenever the public property "lablelText" in LandingController is changed, then try this:
LandingController
#interface LandingController : UIViewController {
}
#property (strong, nonatomic) NSString* lablelText;
- (void)checkForMessages;
#end
#implementation LandingController
#synthesize lablelText;
- (void)checkForMessages
{
if ( //some condition here ){
//update CurrentZone.text label in GuardMenu view and set equal to "Y"
self.lablelText = #"Y";
} else {
//no need to update label in GuardMenu as it's currently equal to "N"
self.lablelText = #"N";
}
}
#end
GuardMenu
#interface GuardMenu : UIViewController {
}
#property (strong, nonatomic) IBOutlet UILabel* nameLabel;
- (IBAction) methodToHandleEvent:(id)sender;
#end
#implementation GuardMenu
- (IBAction) methodToHandleEvent:(id)sender{
LandingController* tempVC = [[LandingController alloc]init];
[tempVC addObserver:self forKeyPath:#"lablelText" options:NSKeyValueObservingOptionNew context:NULL];
[self.navigationController pushViewController:tempVC animated:YES];
}
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
// Here you will be notified everytime lablelText changes
if ([keyPath isEqual:#"lablelText"]) {
NSString* changedName = [change objectForKey:NSKeyValueChangeNewKey];
// do something with the changedName - call a method or update the UI here
self.nameLabel.text = changedName;
}
}
#end
As an alternative for this you can use NSNotificationCeneter to pass notifications from one class to another for some event.
For this you can check my detailed answer How to pass Notifications from one class to another for some event.
Hope it helps you.
Create a notification in the init of GuardMenu class
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"UpdateCurrentZoneNotification"
object:nil];
In the LandingController,
(void)checkForMessages
{
if ( //some condition here ){
[[NSNotificationCenter defaultCenter] postNotificationName:#"UpdateCurrentZoneNotification"
object:nil];
//update CurrentZone.text label in GuardMenu view and set equal to "Y"
} else {
//no need to update label in GuardMenu as it's currently equal to "N"
}
}

Subclass a zooming UIScrollView without delegate methods

I want to implement a UIScrollView subclass to present some custom formatted content. I just set a model object property of the scroll view and it handles all the required layout and rendering to display the content.
This works fine, but now I'd like to include zooming. According to the documentation, to support zooming you have to set a delegate and implement the viewForZoomingInScrollView: method. I guess I could set the delegate to the scroll view itself and implement that method in the subclass. But doing that I would lose the ability to have an external delegate (like an encapsulating UIViewController) that can be notified about scroll events.
Assuming the documentation is right and there is absolutely no (documented) way to implement zooming without a delegate, how could I still retain the possibility of having a regular, unrelated delegate?
Building upon H2CO3's suggestion of saving a hidden pointer to the real delegate and forwarding all incoming messages to it, I came up with the following solution.
Declare a private delegate variable to store a reference to the "real" delegate that is passed in to the setDelegate: method:
#interface BFWaveScrollView ()
#property (nonatomic, weak) id<UIScrollViewDelegate> ownDelegate;
#end
Set the delegate to self to be notified about scrolling events. Use super, so the original setDelegate: implementation is called, and not our modified one.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[super setDelegate:self];
}
return self;
}
Override setDelegate: to save a reference to the "real" delegate.
- (void)setDelegate:(id<UIScrollViewDelegate>)delegate {
_ownDelegate = delegate;
}
When the UIScrollView tries to call a method of its delegate, it will first check to see if the delegate respondsToSelector:. We have to forward this to the real delegate if the selector is part of the UIScrollViewDelegate protocol (Don't forget to #import <objc/runtime.h>).
- (BOOL)selectorIsScrollViewDelegateMethod:(SEL)selector {
Protocol *protocol = objc_getProtocol("UIScrollViewDelegate");
struct objc_method_description description = protocol_getMethodDescription(
protocol, selector, NO, YES);
return (description.name != NULL);
}
- (BOOL)respondsToSelector:(SEL)selector {
if ([self selectorIsScrollViewDelegateMethod:selector]) {
return [_ownDelegate respondsToSelector:selector] ||
[super respondsToSelector:selector];
}
return [super respondsToSelector:selector];
}
Finally, forward all delegate methods to the real delegate that are not implemented in the subclass:
- (id)forwardingTargetForSelector:(SEL)selector {
if ([self selectorIsScrollViewDelegateMethod:selector]) {
return _ownDelegate;
}
return [super forwardingTargetForSelector:selector];
}
Don't forget to manually forward those delegate methods that are implemented by the subclass.
I'd abuse the fact that I'm being a subclass (on purpose :P). So you can hack it. Really bad, and I should feel bad for proposing this solution.
#interface MyHackishScrollView: UIScrollView {
id <UIScrollViewDelegate> ownDelegate;
}
#end
#implementation MyHackishScrollView
- (void)setDelegate:(id <UIScrollViewDelegate>)newDel
{
ownDelegate = newDel;
[super setDelegate:self];
}
- (UIView *)viewForScrollingInScrollView:(UIScrollView *)sv
{
return whateverYouWant;
}
// and then implement all the delegate methods
// something like this:
- (void)scrollViewDidScroll:(UIScrollView *)sv
{
[ownDelegate scrollViewDidScroll:self];
}
// etc.
#end
Maybe this is easier to read and understand a couple of weeks later :)
(sample code for intercepting locationManager:didUpdateLocations: in a subclass)
Other than that the same handling for setting self as delegate to the superclass and intercepting setDelegate in order to save the user's delegate to mDelegate.
EDIT:
-(BOOL)respondsToSelector:(SEL)selector {
if (sel_isEqual(selector, #selector(locationManager:didUpdateLocations:)))
return true;
return [mDelegate respondsToSelector:selector];
}
- (id)forwardingTargetForSelector:(SEL)selector {
if (sel_isEqual(selector, #selector(locationManager:didUpdateLocations:)))
return self;
return mDelegate;
}

Resources