我在我的项目中使用UISpec进行自动化测试。在 Apple 发布带有 iOS 6 SDK 的 xCode 4.5 之前,一切都很好。现在 UISpec 项目无法编译,因为 UITouch 类中的错误列表。这是代码:
//
// TouchSynthesis.m
// SelfTesting
//
// Created by Matt Gallagher on 23/11/08.
// Copyright 2008 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file, free of charge, in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
@implementation UITouch (Synthesize)
//
// initInView:phase:
//
// Creats a UITouch, centered on the specified view, in the view's window.
// Sets the phase as specified.
//
- (id)initInView:(UIView *)view
{
self = [super init];
if (self != nil)
{
CGRect frameInWindow;
if ([view isKindOfClass:[UIWindow class]])
{
frameInWindow = view.frame;
}
else
{
frameInWindow =
[view.window convertRect:view.frame fromView:view.superview];
}
_tapCount = 1;
_locationInWindow =
CGPointMake(
frameInWindow.origin.x + 0.5 * frameInWindow.size.width,
frameInWindow.origin.y + 0.5 * frameInWindow.size.height);
_previousLocationInWindow = _locationInWindow;
UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];
_window = [view.window retain];
_view = [target retain];
_phase = UITouchPhaseBegan;
_touchFlags._firstTouchForView = 1;
_touchFlags._isTap = 1;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
return self;
}
//
// setPhase:
//
// Setter to allow access to the _phase member.
//
- (void)setPhase:(UITouchPhase)phase
{
_phase = phase;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
//
// setPhase:
//
// Setter to allow access to the _locationInWindow member.
//
- (void)setLocationInWindow:(CGPoint)location
{
_previousLocationInWindow = _locationInWindow;
_locationInWindow = location;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
@end
编译器在“_tapCount = 1;”之类的行上给出错误 错误是“未知类型名称“_tapCount”;您的意思是......?”
我做了什么:
- 使用运行时函数“class_copyIvarList”获取 UITouch 类的实例变量列表,并检查这些变量是否仍然存在。他们是这样。
试图在运行时更改所需的值,例如
uint uPhase = UITouchPhaseBegin; object_setInstanceVariable(self, "_phase", &uPhase);
或者
Ivar var = class_getInstanceVariable([self class], "_phase");
object_setIvar(self, var, [NSNumber numberWithInt:UITouchPhaseBegin]);
在这两种情况下,都将无效值写入“_phase”成员。我通过将 UITouch 实例的描述打印到控制台来检查这一点。它被写成“阶段:未知”。
然后我决定尝试键值编码并像这样实现它:
[self setValue:[NSNumber numberWithInt:1] forKey:@"tapCount"];
[self setValue:[NSNumber numberWithInt:UITouchPhaseBegin] forKey:@"phase"];
现在它给出了一些结果。编译错误被消除,UITouch 实例的成员值被改变但仍然没有任何反应。我在适当的 UI 对象(在我的例子中是 UIButton)的“touchesBegan:...”和“touchesEnded:...”方法中设置断点并调试它。这些方法被调用,但没有任何反应 - 按钮处理程序未被调用。
同样由于 KVC,我不得不注释 UITouch 类别的方法“setPhase”和“setLocationInWindow”,否则会发生无休止的递归。属性的 setter 调用自身。
现在我没有想法了。此类别是“由 Matt Gallagher 于 2008 年 11 月 23 日创建。”,这意味着它是 UISpec 的第三方代码。所以我希望它在除 UISpec 之外的其他地方使用,并且有人知道解决方法。
谢谢。
PS我知道这是一个私有API。它不包含在项目的发布配置中。我只需要它来进行自动化测试