UIViewController子类不能分配实例变量

时间:2012-02-28 13:21:28

标签: objective-c ios uiviewcontroller subclass

这让我感到非常困惑,让我觉得我错过了一些必不可少的东西。但我正在尝试创建一个视图控制器容器来管理两个窗格(类似于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?

出于好奇(因为我可以......我几乎没有开始编写课程)我将super从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容器类,想想可能它与类UIViewController的iVars提出了问题。但同样的问题仍然存在。因此将UIViewController包装到另一个变量中不起作用。我也尝试将iVar类型更改为'id',但问题仍然存在。

我还要注意,我已经清理了项目并使用了clang静态分析器来检查逻辑错误。

更新3 此类中的所有赋值都是“关闭”...通常(但不总是)在列表中分配下一个iVar。我放入一堆虚拟id 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 个答案:

答案 0 :(得分:9)

好的,我发现了问题。我正在使用Xcode 4.3,它应该允许你在iOS上使用lldb调试器(或Apple说)。当我将调试器更改为GDB时,我的问题就消失了。虽然现在我有一个有用的调试器,但我意识到分配实际上正常工作。调试器只是吐出不正确的数据。一定要喜欢它。

我的建议:不要在iOS上使用lldb。尽管Apple称lldb调试器可以与iOS一起使用,但它仍然不够稳定,无法依赖。所以是的,我生命中有6个小时......

我向Apple提交了一个错误:10945570

更新

Apple似乎在Xcode 4.3.1中解决了这个问题。至少,到目前为止,LLDB对我来说运作良好。

更新2

不,没关系,LLDB仍然在模拟器中搞砸了。

更新3

据我所知,这个问题现在已经在4.3.2中解决了。我一直在使用LLDB调试器大约一个星期,我没有任何问题,它给我垃圾值。

答案 1 :(得分:2)

此代码似乎不正确:

@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

实际上我可能会把它拿走。不确定它适用于变量..但它适用于方法。

你可以通过在界面

中使用@private来使vars变得私密

修改

我的错误。原始代码是正确的,因为你可以将iVars放在XCode 4.2之后的实现文件中。根据这个问题instance-variables-declared-in-objc-implementation-file,您需要选择4.2+和LLVM。

所以现在我听起来好像不知道我在说什么!

答案 2 :(得分:0)

由于某种原因,#import <UIKit/UIKit.h>不在预编译的标题上,请尝试在其中添加,或者只是在文件顶部添加导入。