2

I'm preparing to submit such a customization by subclassing UIAlerView. It's layout is entirely based on the given topography of the UIAlertView, have no read any private property. Is this kind of customization acceptable by App Store review process?

enter image description here

BGAlertViewWithSwitch.h

//
//  BGAlertViewWithSwitch.h
//  BGAlertViewWithSwitch
//
//  Created by Borbas Geri on 11/7/11.
//  Copyright 2011 ©ompactApps. All rights reserved.
//

#import <Foundation/Foundation.h>


//An assumed value.
#define ALERT_VIEW_LINE_HEIGHT 20.0
#define ALERT_VIEW_LABEL_PADDING 5.0
#define ALERT_VIEW_LABEL_ALPHA 0.5

#define kAlertSwitchLabelTag 42


@interface BGAlertViewWithSwitch : UIAlertView 
{
    UISwitch *_alertSwitch;
    UILabel *_alertSwitchLabel;
}
@property (nonatomic, retain) UISwitch *alertSwitch;
@property (nonatomic, retain) UILabel *alertSwitchLabel;
@property (nonatomic, readonly, getter=isOn) BOOL on;

-(id)initWithTitle:(NSString*) title
           message:(NSString*) message
     switchMessage:(NSString*) switchMessage
          delegate:(id) delegate
 cancelButtonTitle:(NSString*) cancelButtonTitle
     okButtonTitle:(NSString*) okButtonTitle;

@end

BGAlertViewWithSwitch.m

//
//  BGAlertViewWithSwitch.m
//  BGAlertViewWithSwitch
//
//  Created by Borbas Geri on 11/7/11.
//  Copyright 2011 ©ompactApps. All rights reserved.
//


#import "BGAlertViewWithSwitch.h"


@implementation BGAlertViewWithSwitch
@synthesize alertSwitch = _alertSwitch;
@synthesize alertSwitchLabel = _alertSwitchLabel;


#pragma mark - UISwitch Accessor

-(BOOL)isOn
{
    return self.alertSwitch.isOn;
}


#pragma mark - View lifecycle

-(id)initWithTitle:(NSString*) title
           message:(NSString*) message
     switchMessage:(NSString*) switchMessage
          delegate:(id) delegate
 cancelButtonTitle:(NSString*) cancelButtonTitle
     okButtonTitle:(NSString*) okButtonTitle
{

    //For testing layout
    NSString *placeHolder = @"";

    //Append a line to the message that leaves the place for the switch. 
    NSString *_expandedMessage = [NSString stringWithFormat:@"%@\n%@\n%@\n", message, placeHolder, placeHolder];

    if (self = [self initWithTitle:title
                           message:_expandedMessage
                          delegate:delegate
                 cancelButtonTitle:cancelButtonTitle
                 otherButtonTitles:okButtonTitle, nil])
    {
        //Add switch.
        self.alertSwitch = [[UISwitch alloc] init];
        self.alertSwitch.on = YES; 
        [self addSubview:self.alertSwitch];

        //Add label.
        self.alertSwitchLabel = [[UILabel alloc] init];
        self.alertSwitchLabel.text = switchMessage;
        self.alertSwitchLabel.tag = kAlertSwitchLabelTag;
        [self addSubview:self.alertSwitchLabel];
    }
    return self;
}

- (void)dealloc
{
    self.alertSwitch = nil;
    self.alertSwitchLabel = nil;

    [super dealloc];
}


#pragma mark - Topography

- (void)layoutSubviews
{
    NSLog(@"layoutSubviews to (%@)", NSStringFromCGRect(self.frame));

    //Weak link to the message label.
    UILabel *messageLabel;

    //Enumerate subviews to find message label (the base of the topography).
    for (UIView *eachSubview in self.subviews)
        if ([[eachSubview class] isEqual:[UILabel class]])
        {
            UILabel *eachLabel = (UILabel*)eachSubview;
            if (eachLabel.tag != kAlertSwitchLabelTag)
            {
                messageLabel = eachLabel;
                NSLog(@"Each label frame (%@), saying '%@'", NSStringFromCGRect(eachLabel.frame), eachLabel.text);                
            }
        }

    //Center new content.
    CGSize alertSwitchLabelSize = [self.alertSwitchLabel.text sizeWithFont:messageLabel.font];
    float horizontalCentering = (messageLabel.frame.size.width - (alertSwitchLabelSize.width + ALERT_VIEW_LABEL_PADDING + self.alertSwitch.frame.size.width)) / 2;


    //Switch goes to the bottom right.
    float switchVerticalCentering = ((ALERT_VIEW_LINE_HEIGHT * 2 + 1) - self.alertSwitch.frame.size.height ) / 2;
    CGRect alertSwitchFrame = CGRectMake(messageLabel.frame.origin.x + messageLabel.frame.size.width - self.alertSwitch.frame.size.width - horizontalCentering,
                                         messageLabel.frame.origin.y + messageLabel.frame.size.height - self.alertSwitch.frame.size.height - switchVerticalCentering,
                                         self.alertSwitch.frame.size.width,
                                         self.alertSwitch.frame.size.height);
    self.alertSwitch.frame = alertSwitchFrame;

    //Label goes to the bottom left.    
    float switchLabelVerticalCentering = ((ALERT_VIEW_LINE_HEIGHT * 2 + 1) - ALERT_VIEW_LINE_HEIGHT ) / 2;
    CGRect alertSwitchLabelFrame = CGRectMake(round( messageLabel.frame.origin.x + horizontalCentering ),
                                              round( messageLabel.frame.origin.y + messageLabel.frame.size.height - ALERT_VIEW_LINE_HEIGHT - switchLabelVerticalCentering ),
                                              messageLabel.frame.size.width - self.alertSwitch.frame.size.width,
                                              ALERT_VIEW_LINE_HEIGHT); //self.alertSwitchLabel.frame.size.height);
    self.alertSwitchLabel.frame = alertSwitchLabelFrame;

    //Copy message label properties.
    self.alertSwitchLabel.backgroundColor = [UIColor clearColor];   
    self.alertSwitchLabel.textColor = messageLabel.textColor;
    self.alertSwitchLabel.font = messageLabel.font;
    self.alertSwitchLabel.shadowColor = messageLabel.shadowColor;
    self.alertSwitchLabel.shadowOffset = messageLabel.shadowOffset;

    //Weaken.
    self.alertSwitchLabel.alpha = ALERT_VIEW_LABEL_ALPHA;

    [super layoutSubviews];
}


@end
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Geri Borbás
  • 15,810
  • 18
  • 109
  • 172
  • Hey, just a question. Can I use your code in my project? I need exactly the same thing. Thanks a lot – Y2theZ Feb 14 '13 at 11:16

2 Answers2

4

The actual answer to the question is no -- Apple does not allow UIAlertView to be subclassed. From the UIAlertView docs:

Subclassing Notes

The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.

Found here: Subclassing UIAlertView

Community
  • 1
  • 1
mpemburn
  • 2,776
  • 1
  • 35
  • 41
3

No one but Apple can adequately answer this question, so the best thing is to put it to the test. I think the main question you have to ask yourself is: Have I violated any provisions in the Apple Developer Agreement? If not, then submit your app. If you are worried about rejection, think of another way in which this could be done, as a backup, and be prepared to submit that in case of a problem.

Not that you have asked, but I would also opine that this change to Apple's design is not very intuitive. Do you mean the switch to mean "also delete from moquus?" as you already have a big delete button there. If the switch is off, then what does the delete button delete?

Owen Hartnett
  • 5,925
  • 2
  • 19
  • 35
  • Great, thanks. I'll include the word "also". By the way, I simply posted this page to Apple with a question, so it will answered soon I hope. – Geri Borbás Nov 07 '11 at 17:43
  • I changed the word on the screenshot above. :) – Geri Borbás Nov 07 '11 at 17:46
  • Ye' this is not too "natural", but better than create an UIAlertView from the scratch. – Geri Borbás Nov 07 '11 at 17:48
  • Why not just add a third button? "Cancel" "Delete Moquus and moqu.us" "Delete this Moquu" -- Or some other better wording depending on what Moquus are. – Owen Hartnett Nov 07 '11 at 17:52
  • That feels duplicated somehow. Another (and maybe the best) way could be to set this option separated in the App settings, and only a tiny label shows the actual state in the UIAlertView ("Moquus will be deleted from moqu.us also", or the opposite). This intention is not changing too often. – Geri Borbás Nov 07 '11 at 17:56
  • Oh, by the way: http://www.moqu.us – Geri Borbás Nov 07 '11 at 17:58