18

UPDATE: Got a mail from Apple saying that the bug/issue has been fixed now and the next SDK release won't have this issue. Peace!

I have this in the code for my AppDelegate:

- (void) customizeAppearance {
    [[UISwitch appearance] setOnTintColor:[UIColor colorWithRed:0 green:175.0/255.0 blue:176.0/255.0 alpha:1.0]];
    [[UISwitch appearance] setTintColor:[UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:1.000f]];
    [[UISwitch appearance] setThumbTintColor:[UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0]];
 }

Which I then call from - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

I also use ARC. In iOS 6 my app keeps crashing. I enabled NSZombie and it keeps saying: *** -[UIDeviceRGBColor release]: message sent to deallocated instance 0x9658eb0

And now I've realized one perfectly reproducible flow for the above. When I comment out the setThumbTintColor line alone inside customizeAppearance, then everything works fine as it should. When I use the setThumbTintColor line instead, the app crashes the exact same way every time.

Is this a known issue to anyone with UISwitch/setThumbTintColor/UIColor? What else could be the cause if not the switch color?

Bourne
  • 10,094
  • 5
  • 24
  • 51
  • 1
    I don't know why this happens, but if you can reproduce this in a basic example app, you might want to post a bug at http://bugreport.apple.com – Michael Ochs Oct 19 '12 at 10:44
  • See http://www.raywenderlich.com/21703/user-interface-customization-in-ios-6 . Doesn't crash in his sample app. I think this is something else. What I'm messing up in my app, I've no idea. – Bourne Oct 19 '12 at 11:04
  • When does it crash? On calling this lines from your post? If you call this in `-application:didFinishLaunchingWithOptions:` it should be easy to find as there isn't much that has been executed by now. If it crashes somewhere else, it might be interesting to see some of the surrounding code. – Michael Ochs Oct 19 '12 at 11:13
  • The code posted here works fine. The problem must be somewhere else. Did you try to set an **exception breakpoint**? – Andreas Ley Oct 19 '12 at 11:15
  • This still exists. No activity on the filed radar yet. – Bourne Jan 31 '13 at 12:49
  • Any update on the radar? I'm able to reproduce it consistently. –  Jun 18 '13 at 04:23
  • Most likely, Apple's code includes a weak reference that should be strong, because there's no error when thumbTintColor is set to [UIColor redColor]; –  Jun 18 '13 at 04:35
  • Here's the radar that I had filed long ago. Dupe it if you're also facing this issue. rdar://12562867 – Bourne Jun 20 '13 at 10:19
  • Bug fixed in the next release according to Apple. – Bourne Jul 03 '13 at 07:11
  • Thank you very much. This linked me to the UISwitch Bug, otherwise I had to search for ages. – palme Nov 20 '13 at 10:31

3 Answers3

19

I was also doing this tutorial and had the same problem. (Not sure why you don't experience this, as both my hand typed in code and the solution code have the same problem for me?)

The first segue would happen ok, but after going back the next segue would fail.

After setting a global exception breakpoint I could see thumbColorTint in the call stack when the exception was generated. I made a guess that the object was being released too early. To fix I created a property in my app delegate..(you don't need to do it in the app delegate just the object that you are setting the UISwitch appearance, which in my case was the appdelegate)

@interface SurfsUpAppDelegate()
@property (strong, nonatomic) UIColor *thumbTintColor;
@end

Then I set it up as so

[self setThumbTintColor:[UIColor colorWithRed:0.211 green:0.550 blue:1.000 alpha:1.000]];
[[UISwitch appearance] setThumbTintColor:[self thumbTintColor]];

And now everything works as expected as the object is not released early. This is probably a defect and the object is released even though it is still needed. UISwitch seems to have a defect for the API :(

Isuru
  • 30,617
  • 60
  • 187
  • 303
maninvan
  • 890
  • 9
  • 10
  • This solves the issue. Hence accepted. I also found one more workaround. Setting the switch's parent view to strong prevents the crash as well. I went ahead and filed a bug with a sample project anyway, as this never seems to happen for any other UI element other than a switch and that too only while setting the thumbTintColor property. – Bourne Oct 28 '12 at 13:50
  • 1
    I also have the same issue. Both Bill and Bourne's solutions work for me. However, I have another project which contains a navigation controller. 5 view controllers are in the stack and sometimes the view could be pushed/popped. When either scene contains the switch. Neither the above solutions works. I think we just wait Apple to fix this. – Wayne Liu Mar 27 '13 at 16:48
  • 1
    This workaround doesn't seem to have any effect for me. My app crashes when switch instances are dealloc'd no matter how I set the thumbTintColor. – metatation Apr 17 '13 at 21:06
  • Sorry it doesn't work in all cases. I suspect that in some cases it released correctly and others not (As Wayne indicates). A bug fix will resolve it once and for all. NONT makes a good suggestion, but this may fail when it is fixed. Memory issues like these are difficult to retro fix. – maninvan May 30 '13 at 03:10
3

I also ran into this bug with Apple's UISwitch over-releasing. I have a similar solution, but I think its just a little bit nicer because it doesn't require the addition of a extraneous property:

UIColor *thumbTintColor =  [[UIColor alloc] initWithRed:red green:green blue:blue alpha:alpha]];

//we're calling retain even though we're in ARC,
// but the compiler doesn't know that

[thumbTintColor performSelector:NSSelectorFromString(@"retain")]; //generates warning, but OK
[[UISwitch appearance] setThumbTintColor:[self thumbTintColor]];

On the downside, it does create a compiler warning, but then - there really is a bug here, just not ours!

nont
  • 9,322
  • 7
  • 62
  • 82
1

For now, I'm going with this per Bill's answer:

// SomeClass.m

@interface SomeClass ()

// ...

@property (weak,   nonatomic) IBOutlet UISwitch *thumbControl;
@property (strong, nonatomic)           UIColor *thumbControlThumbTintColor;

// ...

@end

@implementation SomeClass

// ...

- (void)viewDidLoad
{
    // ...

    self.thumbControl.thumbTintColor = self.thumbControlThumbTintColor = [UIColor colorWithRed:0.2 green:0.0 blue:0.0 alpha:1.0];

    // ...
}

// ...

@end