Подкласс UIViewController не может назначить переменную экземпляра - PullRequest
3 голосов
/ 28 февраля 2012

Это совершенно сбивает меня с толку, заставляет меня думать, что я что-то упустил.Но я пытаюсь создать контейнер контроллера представления для управления двумя панелями (аналогично SplitViewController, но с некоторыми существенными отличиями).Я только начал создавать класс, поэтому сейчас у меня есть только 3 iVars:

@implementation SplitViewController{
    BOOL _showLeftPane;
    UIViewController *_leftController;
    UIViewController *_rightController;
}

Независимо от того, что я делаю, я не могу назначить контроллер представления _leftController iVar.Главным образом, _rightController iVar может назначать.Это страннее.Если я переключу порядок iVars так, чтобы _rightController появился перед _leftController, я не смогу назначить ни одну из них с первой попытки.Однако, если я попытаюсь снова (буквально напишу назначение дважды), то _leftController возьмет.Соответственно, когда я использую консоль для запроса значения первого контроллера, указанного в объявлениях iVar, сразу после назначения, полученное значение равно (UIViewController *) $5 = 0x00000001 [no Objective-C description available].WTF?

Из любопытства (и потому что я могу ... я только начал писать класс) я изменил супер с UIViewController на NSObject.Когда я это делаю, назначение работает.И действительно, присваивание - это почти все, что этот класс делает сейчас, кроме создания пустого представления в loadView.

Чего мне не хватает?

Обновление Остальной код:

Весь файл .h:

#import <UIKit/UIKit.h>

@interface SplitViewController : UIViewController

@property (strong) UIViewController *leftViewController;
@property (strong) UIViewController *rightViewController;
@end

Весь файл .m (обратите внимание, я пробовал синтезировать свойства, такое же поведение, за исключением того, что его сложнее отладить из консоли):

@implementation SplitViewController{
    BOOL _showLeftPane;
    UIViewController *_rightNavController;
    UIViewController *_leftNavController;
}
#pragma mark - Init Methods
- (id)init{
    if (self = [super initWithNibName:nil bundle:nil]){
        _showLeftPane = YES;
    }
    return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

    }
    return self;
}

#pragma mark - Properties
- (void) setLeftViewController:(UIViewController *)leftViewController{
    _leftNavController = leftViewController;
}
- (UIViewController *) leftViewController{
    return _leftNavController;
}
- (void) setRightViewController:(UIViewController *)rightViewController{
    _rightNavController = rightViewController;
}
- (UIViewController *) rightViewController{
    return _rightNavController;
}

Первоначально у меня были все обычные переопределенные методы контроллера представления (loadView, viewDidLoad и т. Д.), Но с тех пор я комментировал их, пока не смог решить эту проблему.Кроме того, я использую ARC.

Обновление 2 Я попытался настроить простой контейнерный класс NSObject, думая, что, возможно, это связано с тем, что iVars принадлежит к классу UIViewController, который представляетпроблема.Но та же проблема сохраняется.Так что перенос UIViewController в другую переменную не работает.Я также пытался изменить тип iVar на «id», но проблема сохраняется.

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

Обновление 3 Все назначения в этом классе «выключены» ... часто (но не всегда) назначают следующий iVar в списке.Я добавил кучу фиктивных идентификаторов iVars и назначил им случайные объекты.Затем я прошел каждое назначение (которое я положил в init) и проверил значение до и после назначения:

 if (self = [super initWithNibName:nil bundle:nil]) {
        _showLeftPane = YES;
        _dummy1 = [[NSObject alloc] init];
        _dummy2 = [[UIView alloc] init];
        _dummy3 = [[NSNumber alloc] init];
        _dummy4 = [[NSString alloc] init];
        _dummy5 = [[NSValue alloc] init];
        _dummy6 = [[UIColor alloc] init];
        _dummy7 = [[NSCache alloc] init];
        _dummy8 = [[UIButton alloc] init];
        _dummy9 = [[UIFont alloc] init];
        _rightController = [[UIViewController alloc] init];
        _leftController = [[UIViewController alloc] init];
    }

Это то, что я получил (не значения не меняются после назначения, но те, которыеесть значения часто из предыдущего назначения).:

(lldb) po _showLeftPane
(BOOL) $2 = '\0' <nil>
(lldb) po _showLeftPane
(BOOL) $4 = '\0' <nil>
(lldb) po _dummy1
(id) $6 = 0x00000001 [no Objective-C description available]
(lldb) po _dummy1
(id) $8 = 0x00000001 [no Objective-C description available]
(lldb) po _dummy2
(id) $9 = 0x0a0461e0 <NSObject: 0xa0461e0>
(lldb) po _dummy2
(id) $11 = 0x0a0461e0 <NSObject: 0xa0461e0>
(lldb) po _dummy3
(id) $12 = 0x0866f340 <UIView: 0x866f340; frame = (0 0; 0 0); layer = <CALayer: 0xa05a790>>
(lldb) po _dummy3
(id) $14 = 0x0866f340 <UIView: 0x866f340; frame = (0 0; 0 0); layer = <CALayer: 0xa05a790>>
(lldb) po _dummy4
(id) $15 = 0x00000000 <nil>
(lldb) po _dummy4
(id) $17 = 0x00000000 <nil>
(lldb) po _dummy5
(id) $18 = 0x017c5a7c <object returned empty description>
(lldb) po _dummy5
(id) $20 = 0x017c5a7c <object returned empty description>
(lldb) po _dummy6
(id) $21 = 0x00000000 <nil>
(lldb) po _dummy6
(id) $23 = 0x00000000 <nil>
(lldb) po _dummy7
(id) $24 = 0x0865d300 <UIPlaceholderColor: 0x865d300>
(lldb) po _dummy7
(id) $26 = 0x0865d300 <UIPlaceholderColor: 0x865d300>
(lldb) po _dummy8
(id) $27 = 0x0a230af0 <NSCache: 0xa230af0>
(lldb) po _dummy8
(id) $29 = 0x0a230af0 <NSCache: 0xa230af0>
(lldb) po _dummy9
(id) $30 = 0x08637350 <UIButton: 0x8637350; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x8484920>>
(lldb) po _dummy9
(id) $32 = 0x08637350 <UIButton: 0x8637350; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x8484920>>
(lldb) po _rightController
(UIViewController *) $33 = 0x00000000 <nil>
(lldb) po _rightController
(UIViewController *) $35 = 0x00000000 <nil>
(lldb) po _leftController
(UIViewController *) $36 = 0x0a065180 <UIViewController: 0xa065180>
(lldb) po _leftController
(UIViewController *) $38 = 0x0a065180 <UIViewController: 0xa065180>

Итак ... это ошибка?Если так, как, черт возьми, я бы подал это?Я даже не знаю, что происходит ....

Обновление 4 Я получил его на работу, но только на моем устройстве.Я обычно склонен вносить серьезные изменения в симулятор сначала (легче / быстрее отлаживать), а затем тестировать его на работоспособность на устройстве.Кроме того, я предпочитаю иметь рабочую версию на своем устройстве, чтобы я мог проверить ее в свободное время.Так что я установил его на моем устройстве, и класс работает нормально.Кажется, только в симуляторе.Любые идеи о том, почему это может быть?Я действительно не хочу испытывать остальную часть моей разработки программы на одном устройстве.Это немного замедлит ход событий.

Ответы [ 3 ]

9 голосов
/ 28 февраля 2012

Хорошо, я понял проблему. Я использую Xcode 4.3, который должен позволить вам использовать отладчик lldb с iOS (или так Apple говорит). Моя проблема ушла, когда я изменил отладчик на GDB. Хотя теперь у меня есть полезный отладчик, я понял, что назначения на самом деле работают правильно. Отладчик просто выплевывал неверные данные. Должен любить это.

Мой совет: не используйте lldb на iOS. Хотя Apple заявляет, что отладчик lldb можно использовать с iOS, он все еще недостаточно стабилен, чтобы на него можно было положиться. Так что да, прошло 6 часов моей жизни ....

Я подал ошибку в Apple: 10945570

UPDATE

Apple, похоже, исправила это в Xcode 4.3.1. По крайней мере, пока LLDB работает хорошо для меня.

ОБНОВЛЕНИЕ 2

Нет, неважно, LLDB все еще запутался в симуляторе.

ОБНОВЛЕНИЕ 3

Насколько я могу судить, эта проблема теперь решена в 4.3.2. Я пользуюсь отладчиком LLDB уже около недели, и у меня не было проблем с его выдачей значений мусора.

2 голосов
/ 28 февраля 2012

Этот код кажется неправильным:

@interface SplitViewController : UIViewController

@property (strong) UIViewController *leftViewController;
@property (strong) UIViewController *rightViewController;
@end

....

@implementation SplitViewController{
  BOOL _showLeftPane;
  UIViewController *_rightNavController;
  UIViewController *_leftNavController;
}

Это то, что у вас действительно есть?Потому что я ожидал чего-то подобного в .h:

@interface SplitViewController : UIViewController
@property BOOL showLeftPane;
@property (strong) UIViewController* leftViewController;
@property (strong) UIViewController* rightViewController;
@end

И в .m

@implementation SplitViewController
@synthesize showLeftPane;
@synthesize leftViewController;
@synthesize rightViewController;
...
@end

Или если вы хотите использовать явные вспомогательные переменные

@interface SplitViewController : UIViewController
{
    BOOL _showLeftPane;
    UIViewController* _leftViewController;
    UIViewController* _rightViewController;
}

@property BOOL showLeftPane;
@property (strong) UIViewController* leftViewController;
@property (strong) UIViewController* rightViewController;
@end

....

@implementation SplitViewController
@synthesize showLeftPane = _showLeftPane;
@synthesize leftViewController = _leftViewController;
@synthesize rightViewController = _rightViewController;
...
@end

Судя по опубликованному коду, вы путаете понятия между @interface и @implementation

Согласно вашему комментарию, если вы хотите использовать частные переменные, тогда файл .m должен бытьчто-то вроде:

@interface SplitViewController()
{
  BOOL showLeftPane;
  UIViewController* leftViewController;
  UIViewController* rightViewController;
}
@end

....

@implementation SplitViewController
...
@end

На самом деле я, вероятно, заберу это обратно.Не уверен, что он работает для vars .. но он работает для методов.

Вы можете сделать vars закрытым, используя @private в интерфейсе

edit

Моя ошибка.Оригинальный код верен, в том смысле, что вы можете поместить iVars в файл реализации, подобный тому, что был в XCode 4.2В соответствии с этим вопросом SO instance-variable-Объявленный-in-objc-реализационный файл вам нужно 4.2+ и LLVM выбран.

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

0 голосов
/ 28 февраля 2012

Возможно, по какой-то причине #import <UIKit/UIKit.h> отсутствует в ваших предварительно скомпилированных заголовках, попробуйте добавить его туда или просто добавить импорт поверх вашего файла.

...