instructure / CKRefreshControl

A pull-to-refresh view for iOS 5, 100% API-compatible with UIRefreshControl in iOS 6
MIT License
292 stars 57 forks source link

Storyboard refresh control loses tintColor #11

Closed johnhaitas closed 11 years ago

johnhaitas commented 11 years ago

a setTintColor:nil message is passed to the refresh control after the storyboard view controller has loaded.

johnhaitas commented 11 years ago

This call to setTintColor:nil appears to originate from UIAppearance.

The "appearance" has not been set by +appearance or +appearanceWhenContainedIn:[StoryboardViewController class]

#0  0x0000512d in -[CKRefreshControl setTintColor:] at /path/to/CKRefreshControl/CKRefreshControl/CKRefreshControl.m:142
#1  0x012ce51d in __invoking___ ()
#2  0x012ce437 in -[NSInvocation invoke] ()
#3  0x012f949a in -[NSInvocation invokeWithTarget:] ()
#4  0x005f1ddb in workaround10030904InvokeWithTarget ()
#5  0x005f0242 in +[_UIAppearance _applyInvocationsTo:matchingSelector:] ()
#6  0x005f092f in +[_UIAppearance _applyInvocationsTo:] ()
#7  0x0020d2b7 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#8  0x01369e72 in -[NSObject performSelector:withObject:] ()
#9  0x000ed92d in -[CALayer layoutSublayers] ()
#10 0x000f7827 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#11 0x0007dfa7 in CA::Context::commit_transaction(CA::Transaction*) ()
#12 0x0007fea6 in CA::Transaction::commit() ()
#13 0x0010b30c in +[CATransaction flush] ()
#14 0x001df530 in _afterCACommitHandler ()
#15 0x0133c9ce in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#16 0x012d3670 in __CFRunLoopDoObservers ()
#17 0x0129f4f6 in __CFRunLoopRun ()
#18 0x0129edb4 in CFRunLoopRunSpecific ()
#19 0x0129eccb in CFRunLoopRunInMode ()
#20 0x0216d879 in GSEventRunModal ()
#21 0x0216d93e in GSEventRun ()
#22 0x001cea9b in UIApplicationMain ()
#23 0x0000222d in main at /path/to/CKRefreshControl/RefreshControlDemo/main.m:30
johnhaitas commented 11 years ago

One note on i0S 6 behavior. In AppDelegate.h: if you add #import "StoryboardViewController.h" and change line 33 to:

[[UIRefreshControl appearanceWhenContainedIn:[AppearanceCustomizationController class], [StoryboardViewController class], nil] setTintColor:[UIColor greenColor]];

The StoryboardViewController's refresh control is still orange (as set in storyboard) not green (as set in +appearanceWhenContainedIn:)

johnhaitas commented 11 years ago

Here is a working fix: johnhaitas/CKRefreshControl@86f412a28e1540a2814fbf62ec3391976e5463fb (commit message is messed up)

It may look ugly, but CKRefreshControl's tintColor behavior more closely mirrors that of UIRefreshControl in iOS 6.

bjhomer commented 11 years ago

This:

[[UIRefreshControl appearanceWhenContainedIn:[AppearanceCustomizationController class], [StoryboardViewController class], nil] setTintColor:[UIColor greenColor]];

isn't valid; I would not expect that to cause it to set anything to green. That says "Set any refresh controls which are inside AppearanceCustomizationControllers, which in turn are inside StoryboardViewControllers, to green." Since AppearanceCustomizationController is not a child view controller of StoryboardViewController, it doesn't match anything in the app, and the declaration is effectively useless.

johnhaitas commented 11 years ago

Yes, I clearly need to get a better understanding of how the UIAppearance protocol works. Is there a good reference/tutorial you are aware of besides the UIAppearance Protocol Reference?

bjhomer commented 11 years ago

The best thing I know of is the "Customizing the Appearance of UIKit Controls" from the 2011 WWDC videos. (https://developer.apple.com/videos/wwdc/2011/).

bjhomer commented 11 years ago

Also, I believe that if you set a specific tint color in the storyboard, then the appearance proxy will not take effect. It only takes effect if you don't have another tint color set somewhere else. It basically provides a fallback default color.

johnhaitas commented 11 years ago

pull request 12 begins to address this issue

bjhomer commented 11 years ago

Turns out, this is due to a bug in iOS 5 in the +appearance mechanism. If you call +appearanceWhenContainedIn:, but not +appearance, then all instances of the control not matching the "contained in" clause will receive a setFoo = nil call. This has been fixed in iOS 6.0.

I'm going to close this issue, since it's consistent with how everything else works on iOS 5.