Сбой при прокрутке UIPickerView, настроенного с помощью IB - PullRequest
1 голос
/ 07 декабря 2009

Это мой первый раз, когда я использую IB, но, проведя с ним один или два близких дня, думаю, я начинаю понимать это. Это просто мой способ сказать, что я могу упустить что-то простое здесь:

Я настроил UIPickerView и присоединил его к его объекту DataSource и Delegate в IB (оба разных класса в моем случае). Это позволяет средству выбора отображаться, когда я запускаю приложение, что очень обнадеживает, когда оно не появлялось ни в каких предыдущих тестовых прогонах. ;) Однако, когда я прокручиваю UIPickerView, программа вылетает, и я не могу найти ни один из моих кодов, на которые есть ссылки в обратном следе. После некоторого устранения неполадок, я думаю, я сократил аварию до двух отдельных случаев, что касается обратной трассировки:

возвращаемое значение -pickerView: numberOfRowsInComponent:> количество отображаемых строк

  • Приложение вылетает, как только начинается движение, чтобы выбрать новую строку
  • Приложение вылетает, если я пытаюсь использовать -selectRow: inComponent: animated:

обратный ход (без учета основного):

#0  0x955e8688 in objc_msgSend ()
#1  0x0167bea8 in -[UIPickerView table:cellForRow:column:reusing:] ()
#2  0x016773c1 in -[UIPickerView table:cellForRow:column:] ()
#3  0x017fef53 in -[UITable createPreparedCellForRow:column:] ()
#4  0x018077c8 in -[UITable _updateVisibleCellsNow] ()
#5  0x018027cf in -[UITable layoutSubviews] ()
#6  0x03ac42b0 in -[CALayer layoutSublayers] ()
#7  0x03ac406f in CALayerLayoutIfNeeded ()
#8  0x03ac38c6 in CA::Context::commit_transaction ()
#9  0x03ac353a in CA::Transaction::commit ()
#10 0x03acb838 in CA::Transaction::observer_callback ()
#11 0x007b8252 in __CFRunLoopDoObservers ()
#12 0x007b765f in CFRunLoopRunSpecific ()
#13 0x007b6c48 in CFRunLoopRunInMode ()
#14 0x000147ad in GSEventRunModal ()
#15 0x00014872 in GSEventRun ()
#16 0x0168a003 in UIApplicationMain ()

возвращаемое значение -pickerView: numberOfRowsInComponent: <количество отображаемых строк </strong>

  • Приложение вылетает после прекращения движения и выбора строки
  • Приложение не аварийно завершает работу, если я пытаюсь использовать -selectRow: inComponent: animated:

backtrace (без учета основного):

#0  0x955e8688 in objc_msgSend ()
#1  0x0167700d in -[UIPickerView _sendSelectionChangedForComponent:] ()
#2  0x017f4187 in -[UIScroller _scrollAnimationEnded] ()
#3  0x016f732c in -[UIAnimator stopAnimation:] ()
#4  0x016f7154 in -[UIAnimator(Static) _advance:] ()
#5  0x00017739 in HeartbeatTimerCallback ()
#6  0x007b7ac0 in CFRunLoopRunSpecific ()
#7  0x007b6c48 in CFRunLoopRunInMode ()
#8  0x000147ad in GSEventRunModal ()
#9  0x00014872 in GSEventRun ()
#10 0x0168a003 in UIApplicationMain ()

Ниже приведены мои реализации делегатов и источников данных:

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return (NSInteger)3;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return (NSInteger)4;
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
  //it will probably be better to use the method following when creating the rows, so I can better customize it 
    return @"strings";
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    NSLog(@"selected a row");
}

Ответы [ 4 ]

4 голосов
/ 11 декабря 2009

Немного изучил документацию Apple, и это подтвердило мои предыдущие предположения. Из Руководство по программированию ресурсов :

Объекты в файле пера созданы со счетом сохранения 1, а затем autoreleased. Как это восстанавливает иерархия объектов, однако, UIKit восстанавливает связи между объекты, использующие setValue: forKey: метод, который использует доступные метод установки или сохраняет объект по умолчанию, если нет метода установки имеется в наличии. Если вы определяете выходы для объекты nib-файла, вы также должны определить метод установки для доступа эта розетка. Методы установки для торговые точки должны сохранять свои ценности, и методы установки для торговых точек содержащие объекты верхнего уровня должны сохранить свои ценности, чтобы предотвратить их от освобождения. Если вы этого не сделаете хранить объекты верхнего уровня в вы должны сохранить либо массив, возвращаемый loadNibNamed: владелец: опции: метод или объекты внутри массива для предотвратить эти объекты от выпущен преждевременно.

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

Для Mac OS X и UIKit рекомендуемый способ управления объекты верхнего уровня в файле пера создать точки для них в файле Владелец объекта, а затем определить сеттер методы, чтобы сохранить и освободить тех, объекты по мере необходимости. Методы установки дают вы подходящее место для включения ваш код управления памятью, даже в ситуации, когда ваше приложение использует вывоз мусора. Один простой способ реализовать ваши методы сеттера является используйте синтаксис @property и пусть компилятор создаст их для вас.

Я протестировал этот подход в примере кода - определял выходы для объектов делегата и источника данных в классе владельца файла и связывал их в IB. А в классе владельца файла определено свойство для этих торговых точек:

@property (nonatomic, retain) NSObject<UIPickerViewDelegate>* myDelegate;
@property (nonatomic, retain) NSObject<UIPickerViewDataSource>* mySource;

Работал нормально.

0 голосов
/ 24 февраля 2010

Я бы сказал, не слишком подробно изучая, что вы должны убедиться, что каждый объект в IB связан через свойства, которые сохраняются, с владельцем файла.Это причина номер один, которую я видел для сбоев.Как только что-то упоминается или даже не упоминается, но не является каким-либо образом дочерним владельцем файла, это вызывает сбой.Начните без соединений, без делегатов, кроме тех, которые необходимы для создания этой цепочки.Если это работает без сбоев, установите одно соединение, затем протестируйте и повторите.Сбои прокрутки почти всегда происходят, потому что что-то было автоматически освобождено.

Если вы получили объект b без использования [[B alloc] init], ожидайте, что он исчезнет после того, как цикл выполнения продолжится.(После первого раза вы можете прикоснуться к своему виду).Лечение состоит в том, чтобы сказать объекту b сохранить, как правило, после ссылки на него в другом объекте,

-(void)connectTo:(B*)b {
     self.myReference = b
     [B retain];
}

. Другое решение этого вопроса - через IB.в заголовках сделайте это:

@interface a : NSObject{
    id<UIPickerViewDelegate> myReferenceToDelegate;
}

@property(nonatomic, retain) IBOutlet id<UIPickerViewDelegate> myReferenceToDelegate

@end

Затем вам нужно перейти в конструктор интерфейса и перетащить соединение из myReferenceToDelegate на объект A на объект B. После того, как это будет сделано, убедитесь, что владелец файла имеет этот типсоединения с A.

Соединения Thiese Interface Builder могут быть сложными, потому что они не рассказывают вам много о проблеме, и они не делают так много, как вы могли бы сделать за кулисами.

Удачи в решении этого вопроса.

0 голосов
/ 13 декабря 2009

Вы сказали, что делегат вашего сборщика и источник данных - это разные классы. Где вы их настраиваете? В твоем xib или настройке соединений программно? Возможно ли, что объекты, созданные вами для делегата и источника данных, не будут сохранены?

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

Почему вы хотите использовать разные объекты в качестве делегата и источника данных? Почему бы не реализовать их в самом viewcontroller?

0 голосов
/ 10 декабря 2009

Из вашего последнего комментария может следовать, что делегат для вашего UIPickerView удаляется, и после этого ваш picker.delegate ссылается на недействительную память ...
Возможные решения:

  1. Убедитесь, что ваш объект делегата будет действителен во время использования вашего средства выбора - сохраните его где-нибудь и отпустите, когда ваш средство выбора уничтожается (например, в методе dealloc контроллера родительского представления средства выбора)
  2. В вашем методе dealloc задайте для свойства делегата средства выбора значение nil - оно должно удалить аварийное завершение, но оно также прекратит обработку событий средства выбора.
...