Добавить UIPickerView и кнопку в листе действий - как?

120

Мое приложение требует, чтобы в лист действий были добавлены следующие элементы.

  • UIToolbar
  • Кнопка на UIToolbar
  • UIPicker Control

Я добавил изображение, чтобы понять мои требования.

альтернативный текст

Не могли бы вы объяснить, как это можно реализовать?

Сагар Р. Котари
источник
3
Спасибо, что разместили эту интересную задачу!
Tuyen Nguyen
Вместо того, чтобы возиться с управлением actionSheet, pickerView и т. Д., Я бы рекомендовал использовать EAActionSheetPicker . Это действительно сильно очищает ваш код.
ebandersen
@eckyzero К сожалению, EAActionSheetPicker, похоже, не работает в iOS 7, есть много ошибок, начинающихся с «недопустимый контекст 0x0.».
Магнус
конечно, это слишком хорошо, чтобы быть правдой ... напугать меня, у меня так сложно
ChuckKelly
EAActionSheetPicker больше не работает.
osxdirk

Ответы:

25

Обновление для iOS 7

Документы Apple для UIActionSheet :UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy

Я рекомендую не пытаться настраивать содержимое ActionSheet, поскольку это может привести к серьезным ошибкам недопустимого контекста в iOS 7. Я просто потратил несколько часов на решение этой проблемы и в конечном итоге решил использовать другой подход. Я заменил вызов для отображения листа действий на контроллер модального представления, содержащий простое табличное представление.

Есть много способов добиться этого. Вот один из способов, который я только что реализовал в текущем проекте. Это приятно, потому что я могу повторно использовать его на 5 или 6 разных экранах, где все пользователи могут выбирать из списка параметров.

  1. Создайте новый подкласс UITableViewController, SimpleTableViewController.
  2. Создайте UITableViewController в раскадровке (встроенной в контроллер навигации) и установите для его настраиваемого класса SimpleTableViewController.
  3. Дайте контроллеру навигации для SimpleTableViewController идентификатор раскадровки "SimpleTableVC".
  4. В SimpleTableViewController.h создайте свойство NSArray, которое будет представлять данные в таблице.
  5. Также в SimpleTableViewController.h создайте протокол SimpleTableViewControllerDelegateс требуемым методом itemSelectedatRow:и слабым свойством, называемым делегатом типа id<SimpleTableViewControllerDelegate>. Таким образом мы передадим выбор обратно родительскому контроллеру.
  6. В SimpleTableViewController.m, реализация источника данных Tableview и делегировать методы, вызывая itemSelectedatRow:в tableView:didSelectRowAtIndexPath:.

Дополнительным преимуществом этого подхода является возможность многократного использования. Для использования импортируйте класс SimpleTableViewController в свой ViewController.h, согласитесь с SimpleTableViewDelegate и реализуйте itemSelectedAtRow:метод. Затем, чтобы открыть модальное окно, просто создайте экземпляр нового SimpleTableViewController, установите данные таблицы и делегируйте их, а затем представьте их.

UINavigationController *navigationController = (UINavigationController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SimpleTableVC"];
SimpleTableViewController *tableViewController = (SimpleTableViewController *)[[navigationController viewControllers] objectAtIndex:0];
tableViewController.tableData = self.statesArray;
tableViewController.navigationItem.title = @"States";
tableViewController.delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];

Создаю простой пример и размещаю на github .

Также см. Отображение таблицы действий вызывает ошибки недопустимого контекста CGContext .

Кайл Клегг
источник
2
Ах, iOS 7! Вы испортили все, что было разработано до сих пор. :(
Сагар Р. Котари
@Kyle Не могли бы вы расширить свой ответ, рассказав, каков был ваш подход? Спасибо
Даниэль Санчес
1
@DanielSanchez Обновлено с альтернативным предложением и образцом кода.
Кайл Клегг
3
Гораздо более элегантное решение IMHO - установить представление ввода текстового поля для UIPickerView и его аксессуар для UIToolbar. Вы можете ознакомиться с примером проекта QuickDialog.
Стив Мозер
111

Еще одно решение:

  • нет панели инструментов, но есть сегментированный элемент управления (eyecandy)

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil 
                                                        delegate:nil
                                                        cancelButtonTitle:nil
                                                        destructiveButtonTitle:nil
                                                        otherButtonTitles:nil];
    
    [actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
    
    CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
    
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
    pickerView.showsSelectionIndicator = YES;
    pickerView.dataSource = self;
    pickerView.delegate = self;
    
    [actionSheet addSubview:pickerView];
    [pickerView release];
    
    UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Close"]];
    closeButton.momentary = YES; 
    closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
    closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
    closeButton.tintColor = [UIColor blackColor];
    [closeButton addTarget:self action:@selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
    [actionSheet addSubview:closeButton];
    [closeButton release];
    
    [actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
    
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    
Марсио
источник
1
Я получаю, что приложение UIApplication может не реагировать на предупреждение главного окна, и приложение завершается.
Махеш Бабу
Я пытаюсь использовать UIPickerView, но не могу интегрировать его в свое приложение. Я хочу, чтобы UIPickerView отображался при нажатии кнопки, действие которой зарегистрировано в MYViewController: UIViewController. В методе действия я поместил приведенный выше код pickerview. что мне еще делать? Пожалуйста помоги.
Намрата
1
На самом деле, Фредрик, вы должны использовать [[UIApplication sharedApplication] keyWindow]. Отредактированный источник, чтобы изменить это.
Эрик Голдберг
3
Ван Дю Тран - (недействительно) dismissActionSheet: (UISegmentedControl *) отправитель { UIActionSheet actionSheet = (UIActionSheet ) [ супервизор отправителя]; [actionSheet dismissWithClickedButtonIndex: 0 анимировано: ДА]; }
WINSergey 04
1
Внимание: это вызывает множество ошибок CGContext в iOS 7. См. Stackoverflow.com/questions/19129091/…
Кайл Клегг
75

Несмотря на то, что это старый вопрос, я быстро упомяну, что я собрал класс ActionSheetPicker с удобной функцией, поэтому вы можете создать ActionSheet с UIPickerView в одной строке. Он основан на коде из ответов на этот вопрос.

Изменить: теперь он также поддерживает использование DatePicker и DistancePicker.


UPD:

Эта версия устарела: используйте вместо нее ActionSheetPicker-3.0 .

анимация

TimCinel
источник
1
Супер ... используя это в моем приложении.
Майкл Моррисон
Потрясающие. Используя это сейчас.
Джеймс Скидмор
@ Больной, мне нужно добавить ваше имя в свой проект, если я использую ваш код, спасибо
vinothp
Здравствуйте, я использую этот класс в своем приложении, и он отлично работает. Спасибо. У меня есть вопрос. В ActionSheetDatePickerрежиме вы можете добавить несколько кнопок на панель инструментов сверху. Возможно ли это и с обычным ActionSheetStringPicker?
Isuru
Может ли он делать множественный выбор?
Кайл Клегг
32

Ага ! Наконец-то нахожу.

реализуйте следующий код в событии нажатия кнопки, чтобы отобразить лист действий, как показано на изображении вопроса.

UIActionSheet *aac = [[UIActionSheet alloc] initWithTitle:@"How many?"
                                             delegate:self
                                    cancelButtonTitle:nil
                               destructiveButtonTitle:nil
                                    otherButtonTitles:nil];

UIDatePicker *theDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
if(IsDateSelected==YES)
{
    theDatePicker.datePickerMode = UIDatePickerModeDate;
    theDatePicker.maximumDate=[NSDate date];
}else {
    theDatePicker.datePickerMode = UIDatePickerModeTime;
}

self.dtpicker = theDatePicker;
[theDatePicker release];
[dtpicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];

pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
pickerDateToolbar.barStyle = UIBarStyleBlackOpaque;
[pickerDateToolbar sizeToFit];

NSMutableArray *barItems = [[NSMutableArray alloc] init];

UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
[barItems addObject:flexSpace];

UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(DatePickerDoneClick)];
[barItems addObject:doneBtn];

[pickerDateToolbar setItems:barItems animated:YES];

[aac addSubview:pickerDateToolbar];
[aac addSubview:dtpicker];
[aac showInView:self.view];
[aac setBounds:CGRectMake(0,0,320, 464)];
Сагар Р. Котари
источник
привет, Сагар, спасибо за код, событие кнопки DatePickerDoneClick, как объявить это спасибо
Apache
sagar, как закрыть всплывающий лист действий и добавить выбранное значение в текстовое поле, спасибо
Apache
[aac dimisswithclickedindex] // что-то вроде этого метода. (см. Я разместил кнопку «Готово» на листе действий и добавил целевую кнопку «Готово» - селектор и в селектор разместил код dimissal.
Сагар Р. Котари
спасибо за ответ sagar, я добавляю [aac dismissWithClickedButtonIndex]; но я получаю предупреждение: 'UIActionSheet' может не отвечать на '-dismissWithClickedButtonIndex', тогда я создаю новый метод для селектора 'DatePickerDoneClick', как показано ниже - (void) DatePickerDoneClick {NSLog (@ "Done clicked"); rating.text = pickerView objectAtIndex: row]} что мне делать, чтобы, когда я нажимаю кнопку «Готово», UIActionSheet (aac) отклоняет и текстовое поле (rating.text) заполняется выбранным значением из средства выбора, спасибо sagar
Apache,
1
@Spark, можно ли дать какое-то представление о получении текста в
сборщике
10

Отличное решение Марсио на этот вопрос очень помогло мне в добавлении любых подвидов в таблицу UIActionSheet.

По причинам, которые (пока) мне не совсем понятны, границы UIActionSheet могут быть установлены только после того, как он был отображен; оба решения sagar и marcio успешно решают эту проблему с помощью сообщения setBounds: CGRectMake (...), отправляемого в таблицу действий после его отображения.

Однако установка границ UIActionSheet после того, как лист был отображен, создает скачкообразный переход при появлении ActionSheet, где он «появляется» в поле зрения, а затем прокручивается только на последних 40 пикселях или около того.

При изменении размера UIPickerView после добавления подпредставлений я рекомендую обернуть сообщение setBounds, отправленное в actionSheet, внутри блока анимации. Это сделает вход в actionSheet более плавным.

UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];


// add one or more subviews to the UIActionSheet
// this could be a UIPickerView, or UISegmentedControl buttons, or any other 
// UIView.  Here, let's just assume it's already set up and is called 
// (UIView *)mySubView
[actionSheet addSubview:myView];

// show the actionSheet
[actionSheet showInView:[UIApplication mainWindow]];


// Size the actionSheet with smooth animation
    [UIView beginAnimations:nil context:nil];
    [actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    [UIView commitAnimations]; 
тростник
источник
6
Это отличный совет. В iOS 4 и более поздних версиях этот стиль анимации «не рекомендуется», как указано в документации. Под iOS 4 или новее попробуйте следующее: UIView animateWithDuration: 0.3f delay: 0 options: UIViewAnimationOptionCurveEaseInOut анимации: ^ {[actionSheet setBounds: CGRectMake (0,0,320,485)];} завершение: NULL];
ceperry
9

Для тех парней, которые пытаются найти функцию DatePickerDoneClick ... вот простой код, чтобы закрыть лист действий. Очевидно, что aac должен быть ivar (тот, который входит в ваш файл с расширением .h)


- (void)DatePickerDoneClick:(id)sender{
    [aac dismissWithClickedButtonIndex:0 animated:YES];
}
Accilies
источник
9

Я действительно не понимаю, почему UIPickerViewвнутри UIActionSheet. Это кажется беспорядочным и хакерским решением, которое может быть взломано в будущем выпуске iOS. (У меня были такие вещи, как этот перерыв в приложении раньше, где UIPickerViewне отображалось при первом нажатии, и его приходилось исправлять - странные причуды с UIActionSheet).

Я просто реализовал a, UIPickerViewа затем добавил его в качестве подпредставления к моему представлению и оживил его, двигаясь вверх, как если бы он был представлен как лист действий.

/// Add the PickerView as a private variable
@interface EMYourClassName ()

@property (nonatomic, strong) UIPickerView *picker;
@property (nonatomic, strong) UIButton *backgroundTapButton;

@end

///
/// This is your action which will present the picker view
///
- (IBAction)showPickerView:(id)sender {

    // Uses the default UIPickerView frame.
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectZero];

    // Place the Pickerview off the bottom of the screen, in the middle set the datasource delegate and indicator
    _picker.center = CGPointMake([[UIScreen mainScreen] bounds].size.width / 2.0, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;

    // Create the toolbar and place it at -44, so it rests "above" the pickerview.
    // Borrowed from @Spark, thanks!
    UIToolbar *pickerDateToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -44, 320, 44)];
    pickerDateToolbar.barStyle = UIBarStyleBlackTranslucent;
    [pickerDateToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The action can whatever you want, but it should dimiss the picker.
    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(backgroundTapped:)];
    [barItems addObject:doneBtn];

    [pickerDateToolbar setItems:barItems animated:YES];
    [_picker addSubview:pickerDateToolbar];

    // If you have a UITabBarController, you should add the picker as a subview of it
    // so it appears to go over the tabbar, not under it. Otherwise you can add it to 
    // self.view
    [self.tabBarController.view addSubview:_picker];

    // Animate it moving up
    [UIView animateWithDuration:.3 animations:^{
        [_picker setCenter:CGPointMake(160, [[UIScreen mainScreen] bounds].size.height - 148)]; //148 seems to put it in place just right.
    } completion:^(BOOL finished) {
        // When done, place an invisible button on the view behind the picker, so if the
        // user "taps to dismiss" the picker, it will go away. Good user experience!
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(backgroundTapped:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_backgroundTapButton];
    }];

}

// And lastly, the method to hide the picker.  You should handle the picker changing
// in a method with UIControlEventValueChanged on the pickerview.
- (void)backgroundTapped:(id)sender {

    [UIView animateWithDuration:.3 animations:^{
        _picker.center = CGPointMake(160, [[UIScreen mainScreen] bounds].size.height + _picker.frame.size.height);
    } completion:^(BOOL finished) {
        [_picker removeFromSuperview];
        self.picker = nil;
        [self.backgroundTapButton removeFromSuperview];
        self.backgroundTapButton = nil;
    }];
}
Итан Мик
источник
Это большое спасибо. Вы обнаружили, что это нормально работает с iOS 7?
avance
1
+1 за отличный простой вид выбора, анимированный на экране. Но у вас ошибка в коде. Представление backgroundTapButton появляется поверх представления средства выбора и блокирует представление средства выбора от взаимодействия с пользователем. что вы на самом деле хотите сделать, так это сделать это представление на оставшемся пространстве экрана, которое окно выбора еще не заполняет ... (вы не можете создать вид позади
окна выбора,
7

Чтобы добавить к удивительному решению marcio, dismissActionSheet:можно реализовать следующее.

  1. Добавьте объект ActionSheet в свой файл .h, синтезируйте его и укажите ссылку в своем файле .m.
  2. Добавьте этот метод в свой код.

    - (void)dismissActionSheet:(id)sender{
      [_actionSheet dismissWithClickedButtonIndex:0 animated:YES];
      [_myButton setTitle:@"new title"]; //set to selected text if wanted
    }
Кайл Клегг
источник
3

Я думаю, это лучший способ сделать это.

ActionSheetPicker-3,0

Это почти то, что предлагают все, но использует блоки, что приятно!

Тони
источник
Что ж, если вы прочтете выше, вы увидите, что этот класс ActionSheetPicker появился в первую очередь благодаря этой теме. Так что да, это лучший способ, благодаря принятому решению (¬_¬). stackoverflow.com/questions/1262574/…
OpenUserX03
2
Похоже, Apple собирается начать применять свое правило о том, что таблицы действий не должны быть подклассами, поскольку я получаю это сообщение об ошибке - «<Error>: CGContextSetFillColorWithColor: недопустимый контекст 0x0. Это серьезная ошибка. Это приложение или используемая им библиотека , использует недопустимый контекст и тем самым способствует общей деградации стабильности и надежности системы. Это замечание любезно: пожалуйста, исправьте эту проблему. В предстоящем обновлении это станет фатальной ошибкой ".
Стюарт П.
@StuartP. см. мой ответ
Кайл Клегг
2

Начиная с iOS 8, вы не можете, это не работает, потому что Apple изменила внутреннюю реализацию UIActionSheet. См. Документацию Apple :

Примечания к подклассам

UIActionSheet не предназначен для разделения на подклассы, и вам не следует добавлять представления в его иерархию . Если вам нужно представить лист с большей настройкой, чем это предусмотрено API UIActionSheet, вы можете создать свой собственный и представить его модально с помощью presentViewController: animated: completed :.

Mutawe
источник
1

Мне понравился подход Wayfarer и flexaddicted, но я обнаружил (как и aZtral), что он не работает, поскольку backgroundTapButton был единственным элементом, который реагировал на взаимодействие с пользователем. Это заставило меня поместить все три его подпредставления: _picker, _pickerToolbar и backgroundTapButton внутрь содержащего представления (всплывающего окна), которое затем анимировалось на экране и за его пределами. Мне также нужна была кнопка «Отмена» на панели _pickerToolbar. Вот соответствующие элементы кода для всплывающего представления (вам необходимо предоставить собственный источник данных средства выбора и методы делегирования).

#define DURATION            0.4
#define PICKERHEIGHT        162.0
#define TOOLBARHEIGHT       44.0

@interface ViewController ()
@property (nonatomic, strong) UIView        *popup;
@property (nonatomic, strong) UIPickerView  *picker;
@property (nonatomic, strong) UIToolbar     *pickerToolbar;
@property (nonatomic, strong) UIButton      *backgroundTapButton;
@end

-(void)viewDidLoad {
    // These are ivars for convenience
    rect = self.view.bounds;
    topNavHeight = self.navigationController.navigationBar.frame.size.height;
    bottomNavHeight = self.navigationController.toolbar.frame.size.height;
    navHeights = topNavHeight + bottomNavHeight;
}

-(void)showPickerView:(id)sender {
    [self createPicker];
    [self createToolbar];

    // create view container
    _popup = [[UIView alloc] initWithFrame:CGRectMake(0.0, topNavHeight, rect.size.width, rect.size.height - navHeights)];
    // Initially put the centre off the bottom of the screen
    _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    [_popup addSubview:_picker];
    [_popup insertSubview:_pickerToolbar aboveSubview:_picker];

    // Animate it moving up
    // This seems to work though I am not sure why I need to take off the topNavHeight
    CGFloat vertCentre = (_popup.frame.size.height - topNavHeight) / 2.0;

    [UIView animateWithDuration:DURATION animations:^{
        // move it to a new point in the middle of the screen
        [_popup setCenter:CGPointMake(rect.size.width / 2.0, vertCentre)];
    } completion:^(BOOL finished) {
        // When done, place an invisible 'button' on the view behind the picker,
        // so if the user "taps to dismiss" the picker, it will go away
        self.backgroundTapButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _backgroundTapButton.frame = CGRectMake(0, 0, _popup.frame.size.width, _popup.frame.size.height);
        [_backgroundTapButton addTarget:self action:@selector(doneAction:) forControlEvents:UIControlEventTouchUpInside];
        [_popup insertSubview:_backgroundTapButton belowSubview:_picker];
        [self.view addSubview:_popup];
    }];
}

-(void)createPicker {
    // To use the default UIPickerView frame of 216px set frame to CGRectZero, but we want the 162px height one
    CGFloat     pickerStartY = rect.size.height - navHeights - PICKERHEIGHT;
    self.picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0, pickerStartY, rect.size.width, PICKERHEIGHT)];
    _picker.dataSource = self;
    _picker.delegate = self;
    _picker.showsSelectionIndicator = YES;
    // Otherwise you can see the view underneath the picker
    _picker.backgroundColor = [UIColor whiteColor];
    _picker.alpha = 1.0f;
}

-(void)createToolbar {
    CGFloat     toolbarStartY = rect.size.height - navHeights - PICKERHEIGHT - TOOLBARHEIGHT;
    _pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, toolbarStartY, rect.size.width, TOOLBARHEIGHT)];
    [_pickerToolbar sizeToFit];

    NSMutableArray *barItems = [[NSMutableArray alloc] init];
    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction:)];
    [barItems addObject:cancelButton];

    // Flexible space to make the done button go on the right
    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
    [barItems addObject:flexSpace];

    // The done button
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneAction:)];
    [barItems addObject:doneButton];
    [_pickerToolbar setItems:barItems animated:YES];
}

// The method to process the picker, if we have hit done button
- (void)doneAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
    // Do something to process the returned value from your picker
}

// The method to process the picker, if we have hit cancel button
- (void)cancelAction:(id)sender {
    [UIView animateWithDuration:DURATION animations:^{
        _popup.center = CGPointMake(rect.size.width / 2.0, rect.size.height + _popup.frame.size.height / 2.0);
    } completion:^(BOOL finished) { [self destroyPopup]; }];
}

-(void)destroyPopup {
    [_picker removeFromSuperview];
    self.picker = nil;
    [_pickerToolbar removeFromSuperview];
    self.pickerToolbar = nil;
    [self.backgroundTapButton removeFromSuperview];
    self.backgroundTapButton = nil;
    [_popup removeFromSuperview];
    self.popup = nil;
}
VaughanR
источник