18

UIToolBar で UIPickerView を表示しようとしていますが、エラーが発生しています。

ここに私のコードがあります -

CGRect toolbarTargetFrame = CGRectMake(0, self.view.bounds.size.height-216-44, 320, 44);
CGRect datePickerTargetFrame = CGRectMake(0, self.view.bounds.size.height-216, 320, 216);

UIView *darkView = [[UIView alloc] initWithFrame:self.view.bounds];
darkView.alpha = 0;
darkView.backgroundColor = [UIColor blackColor];
darkView.tag = 9;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissDatePicker:)];
[darkView addGestureRecognizer:tapGesture];
[self.view addSubview:darkView];

UIDatePicker *picker = [[UIDatePicker alloc] init];
picker.autoresizingMask = UIViewAutoresizingFlexibleWidth;
picker.datePickerMode = UIDatePickerModeDate;
[picker addTarget:self action:@selector(dueDateChanged:) forControlEvents:UIControlEventValueChanged];
[picker setFrame:CGRectMake(0,235,320,120)];
picker.backgroundColor = [UIColor blackColor];
[self.view addSubview:picker];

UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height, 320, 44)];
toolBar.tag = 11;
toolBar.barStyle = UIBarStyleBlackTranslucent;

UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] ;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissDatePicker:)];

[toolBar setItems:@[spacer, doneButton]];
[self.view addSubview:toolBar];

[UIView beginAnimations:@"MoveIn" context:nil];
toolBar.frame = toolbarTargetFrame;
picker.frame = datePickerTargetFrame;
darkView.alpha = 0.5;
[UIView commitAnimations];

この行でエラーが発生しています -

picker.frame = datePickerTargetFrame;

これはエラーです -

*** Assertion failure in -[UIPickerTableView _createPreparedCellForGlobalRow:withIndexPath:], /SourceCache/UIKit_Sim/UIKit-2903.2/UITableView.m:7768
2013-10-03 13:43:12.688 Mistoh Beta 1[7228:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource is not set'

libc++abi.dylib: terminating with uncaught exception of type NSException

助けてください。よろしくお願いします。

4

6 に答える 6

5

UIDatePicker を inputView として使用しているため、Tao-Nhan から受け入れられた回答がうまくいきませんでした。私は長い間このバグに悩まされてきましたが、今日やっとエレガントな回避策を見つけました!

多くの調査の結果、入力ビューで didMoveToSuperview が呼び出された直後にクラッシュが発生することがわかりました。秘訣は、UIDatePicker を含む「ラッパー」ビューを inputView のサブビューとして使用し、inputView がスーパービューから削除されるのと同じようにピッカーを削除し、移動後に runloop で次の実行時にピッカーを再度追加することです。新しいスーパービュー。ややこしいと思われる場合は、以下のコードを入力ビューとして使用すれば問題ありません。

TL;DR UIDatePicker を inputView として使用していますか? これが私が見つけた回避策です:

GSDatePickerInputView.h :

#import <UIKit/UIKit.h>

@interface GSDatePickerInputView : UIView

@property (nonatomic, readonly) UIDatePicker *datePicker;
@property (nonatomic) BOOL useWorkaroundToAvoidCrash;

@end

GSDatePickerInputView.m :

#import "GSDatePickerInputView.h"

@interface GSDatePickerInputView ()
@property (nonatomic, strong, readwrite) UIDatePicker *datePicker;
@end


@implementation GSDatePickerInputView

- (instancetype)init {
    if (self = [super initWithFrame:CGRectMake(0, 0, 320, 166)]) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        self.backgroundColor = [UIColor whiteColor];
        
        UIDatePicker *datePicker = [[UIDatePicker alloc] init];
        datePicker.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
        datePicker.backgroundColor = [UIColor whiteColor];
        [self addSubview:datePicker];
        self.datePicker = datePicker;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.datePicker.frame = self.bounds;
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (self.useWorkaroundToAvoidCrash == YES) {
        if (newSuperview == nil) {
            [self.datePicker removeFromSuperview];
        }
    }
}

- (void)didMoveToSuperview {
    if (self.useWorkaroundToAvoidCrash == YES) {
        if (self.superview != nil) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self addSubview:self.datePicker];
                self.datePicker.frame = self.bounds;
            });
        }
    }
}

@end

重要な要素は、メソッドwillMoveToSuperview:didMoveToSuperview. GCD 関数は、クラッシュが発生したdispatch_asyncに datePicker を元に戻すために使用されます。

次に、この inputView のインスタンスを次のように使用できます。

GSDatePickerInputView *dateInputView = [[GSDatePickerInputView alloc] init];
dateInputView.useWorkaroundToAvoidCrash = YES;
[dateInputView.datePicker addTarget:self action:@selector(datePickerChanged:) forControlEvents:UIControlEventValueChanged];

yourView.inputView = dateInputView;

そして、次のコードを使用して、後で datePicker 自体にアクセスできます。

((GSDatePickerInputView *)yourView.inputView).datePicker

最後のメモ - プロパティuseWorkaroundToAvoidCrashは、ある場所ではクラッシュしていたが、別の場所ではクラッシュしていなかった場合に備えてあります (これは私に起こりました)。可能な限りそのようなハッカーを避ける方が明らかに良いので、実際にクラッシュしている場所でのみこのプロパティを YES に設定してください。

于 2016-06-24T14:39:47.630 に答える
3

UIDatePicker は、UIPicker を内部で管理します。そのため、メッセージには UIPicker が含まれています。ここで、実際のエラー メッセージに移ります。DatePicker を表示しようとしているときに、十分な余裕がありますか? このエラーがスローされる理由の 1 つは、ビュー全体を表示するのに十分なスペースが見つからない場合です。

于 2013-10-14T19:13:56.623 に答える
2

カスタムUITableViewCellのUIPickerViewにも同じ問題があります。親ビューへのピッカー ビューの配置とその制約の設定を扱っていたすべてのロジックを移動しました。- (void)layoutSubviews

更新後、次のようになりました。

- (void)layoutSubviews
{
    [super layoutSubviews];
    [self addSubview:YOUR_PICKER_VIEW]; //'self' in my case was UITableViewCell
    [self addConstraints:PICKER_VIEW_CONSTRAINTS];
}
于 2015-07-06T10:47:10.713 に答える