Iphone 为什么我的指针被改变了?

Iphone 为什么我的指针被改变了?,iphone,objective-c,pointers,properties,cocos2d-iphone,Iphone,Objective C,Pointers,Properties,Cocos2d Iphone,长话短说,我正在开发一个简单的游戏,我有一个game对象来跟踪当前游戏状态,以及一些以后有用/需要的其他东西。其中之一是对加载游戏的UIViewController的引用,它只是声明为对象上的一个属性: @interface Game : NSObject { //ivars } @property (nonatomic, retain) myViewController* viewController; 此属性的getter/setter是使用@synthesis viewCont

长话短说,我正在开发一个简单的游戏,我有一个
game
对象来跟踪当前游戏状态,以及一些以后有用/需要的其他东西。其中之一是对加载游戏的
UIViewController
的引用,它只是声明为对象上的一个属性:

@interface Game : NSObject {
    //ivars
}

@property (nonatomic, retain) myViewController* viewController;
此属性的getter/setter是使用
@synthesis viewController
生成的,看起来一切正常

现在只有两条路径可以访问此属性,即当游戏赢了和游戏输了。“游戏失败”的路径运行良好。“游戏成功”路径导致了一个奇怪的错误,
viewController
指针的值似乎被垃圾覆盖

为了弄清楚发生了什么,我对getter和setter进行了如下重写:

- (myViewController*) viewController {
    NSLog(@"Getting");
    return viewController;
}

- (void) setViewController:(myViewController*)controller {
    NSLog(@"Setting");
    viewController = controller;
}
…并在内部设置断点(我知道我没有保留视图控制器是我的setter,但这不是问题所在;视图控制器保留在堆栈上,实际上不需要由
游戏
保留)。以下是我在GDB中得到的信息:

//first call to setter
po controller
<myViewController: 0x9208130>

//call to getter on the "game is lost" path
(gdb) po viewController
<myViewController: 0x9208130>

//call to setter, starting a new game from the same view controller
(gdb) po controller
<myViewController: 0x9208130>

//call to getter on the "game is lost" path
(gdb) po viewController
0xbea2222c does not appear to point to a valid object.
(gdb) print viewController
$1 = (myViewController *) 0xbea2222c
//对setter的第一次调用
采购订单管理员
//在“游戏失败”的道路上呼叫getter
(gdb)采购订单视图控制器
//调用setter,从同一视图控制器开始新游戏
(gdb)采购订单控制员
//在“游戏失败”的道路上呼叫getter
(gdb)采购订单视图控制器
0xbea2222c似乎未指向有效对象。
(gdb)打印视图控制器
$1=(myViewController*)0xbea2222c
因此,在某个时刻,指针的值从
0x9208130
更改为
0xbea222c
,但我不知道在哪里。除了游戏开始时对二传手的调用之外,没有代码分配到
viewController
属性(或其支持ivar)。然而,很明显,在“游戏获胜”的路径上,有些东西正在用垃圾覆盖价值

这是否可能是缓冲区溢出问题?如果是的话,什么是追踪它的好方法

编辑


我添加了第二个指针(作为另一个类中的ivar),在游戏开始时将其设置为
game.viewController
的值,并将该指针用于“game is wind”路径。所以在我看来,有什么东西在破坏原始指针。但是仍然不知道是什么。

你的二传手错了。应改为:

- (void) setViewController:(yeticonfettiViewController*)controller {
    NSLog(@"Setting");
    [viewController autorelease];
    viewController = [controller retain];
}

否则,您将永远不会保留控制器,它可能会被垃圾收集。

看起来没有足够的数据来根据您发布的信息诊断问题

如果您想进一步调试这个问题,我建议在指针ivar的内存地址上设置一个断点。这样,如果在您的setter的使用范围之外进行了某种更改,您将收到通知

您可以通过在游戏对象创建过程中的某个点中断并选择在游戏对象的控制器ivar上“查看变量”来完成此操作


另外,还有一个很好的例子,在回答另一个问题时,以类似的方式从Xcode外部使用gdb。

垃圾收集器将对象移动到不同的地址,但这不应影响您的引用,因为引用不会受到影响。@Ryan-我没有使用自动垃圾收集。即使垃圾收集器移动了对象并更新了指针,它也应该指向同一个对象。根据GDB,在
0xbea222c
上存在的任何对象都不再是同一个对象。还有,为什么垃圾收集器只会在“game is won”路径上触发?很抱歉傻瓜的评论,但是你做得对吗?这告诉了你什么?二进制搜索,并用log(n)time查找有问题的行:D@bdares-这难道不需要首先按照怀疑的错误程度对所有行进行排序吗?当然,这只需要做一次,但需要花费超过log(n)的时间来完成。是的,症状完全符合这一点。我想在我的问题中提到,这不是问题所在(使用自动生成的setter执行retain时也会发生同样的情况)。视图控制器始终保留,因为它仍然位于活动视图控制器的堆栈上。
Game
对象中的属性实际上不需要首先声明为
retain
。问题肯定不在于
UIViewController
的发布/释放太早。这是我检查的第一件事。谢谢,这让我解决了问题。这实际上是一个缓冲区溢出问题。基本上,我有一个按级别索引的状态信息数组(每个级别一个条目)。在“game is wind”路径上,级别增加到超过最后一个实际级别,并且对该状态数组的访问超出了边界。解决了这个问题。