我正在尝试重新排列相关方法,包括NSTimer
我之前放在UIViewController
中的相关方法,以使代码更具可读性。我现在需要将它们重新定位到自定义类,以便它们可以独立于ViewController
工作。
但是在我尝试这样做的过程中,我已经介绍了NSTimer的一个问题,即使代码看起来正确也不存在。以下错误日志发生崩溃:
线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x1)
当我尝试使用断点并单步执行代码时,Xcode似乎停留在此语句的循环中
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(nextClock)
userInfo:nil
repeats:YES];
这是我的代码的瘦身版本。 NSTimer
位于名为ConcertController
的类中,该类在PlayViewController.h
PlayViewController.h
#import <UIKit/UIKit.h>
#import "ConcertController.h"
@interface PlayViewController : UIViewController
{
ConcertController *concertStateMachine;
}
@end
并从viewDidLoad
PlayViewController.m
调用
PlayViewController.m
#import "PlayViewController.h"
@implementation PlayViewController {
}
@synthesize lastEventChangeTime;
...
...
- (void)viewDidLoad
{
[super viewDidLoad];
selectedFamily = [parent getSelectedFamily];
selectedPlayerID = [parent getSelectedPlayerID];
concertStateMachine = [[ConcertController alloc] initConcertStateMachine:(int)selectedFamily
forPlayer:(int)selectedPlayerID];
CGRect rect = [UIScreen mainScreen].bounds;
float statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
screenFrame = CGRectMake(0,statusBarHeight,rect.size.width,rect.size.height - statusBarHeight);
self.view = [[UIView alloc] initWithFrame: screenFrame];
}
ConcertController
在PlayViewController.h
ConcertController.h
#import <UIKit/UIKit.h>
@class PlayViewController;
@interface ConcertController : NSObject
{
int currentState;
NSUInteger clockCount;
int totalMinutes;
int totalSeconds;
…
…
NSDate* lastEventChangeTime;
NSTimer* timer;
}
- (id)initConcertStateMachine:(int)selectedFamily
forPlayer:(int)selectedPlayerID;
@property (nonatomic, retain) NSDate *lastEventChangeTime;
@end
ConcertController.m
#import "PlayViewController.h"
@implementation ConcertController
@synthesize lastEventChangeTime;
- (id)initConcertStateMachine:(int)selectedFamily
forPlayer:(int)selectedPlayerID
{
[self findEntryPointsFor:(int)selectedFamily
andPlayer:(int)selectedPlayerID];
[self startClock];
return self;
}
- (void)startClock
{
lastEventChangeTime = [[NSDate alloc] init];
currentState = 0; // CLOCK_Init_CurrentState;
clockCount = 24; // number of seconds per state
totalMinutes = 0 // CLOCK_Init_totalMinutes;
totalSeconds = 0; // CLOCK_Init_totalSeconds;
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(nextClock)
userInfo:nil
repeats:YES];
}
- (void)nextClock
{
lastEventChangeTime = [NSDate date];
clockCount++;
[self masterClockReadout];
if ((clockCount % (int)24) == 0)
{
// [self nextState]; // other (i.e. non-UIView) code goes here
}
}
编辑#2
ConcertController.m中的初始化已按建议标准化。
- (id)initConcertStateMachine:(int)selectedFamily
forPlayer:(int)selectedPlayerID
{
self = [super init];
if (self) {
[self findEntryPointsFor:(int)selectedFamily
andPlayer:(int)selectedPlayerID];
[self startClock];
}
return self;
}
编辑#1。这是一个请求的日志。注意:日志还会显示在已发布的代码示例中找不到的一些项目(为清楚起见,已删除)。格雷格
2017-07-25 17:06:30.809 SatGam2[5476:1809452] FamilySelectViewController loaded
2017-07-25 17:06:34.361 SatGam2[5476:1809452] PlayerIDSelectViewController loaded
2017-07-25 17:06:36.250 SatGam2[5476:1809452] SyncViewController loaded (Family 1 PlayerID 1)
2017-07-25 17:06:38.376 SatGam2[5476:1809452] Initialising MotionListener
2017-07-25 17:06:38.674444+1000 SatGam2[5476:1811506] [aqme] 254: AQDefaultDevice (1): skipping input stream 0 0 0x0
2017-07-25 17:06:38.692 SatGam2[5476:1809452] PlayViewController init called and AudioSession active
2017-07-25 17:06:38.693 SatGam2[5476:1809452] MIDI Event [tuningTransposition: 1 assignedPitches: 1]
2017-07-25 17:06:38.694 SatGam2[5476:1809452] Selected octave is 2
2017-07-25 17:06:38.694 SatGam2[5476:1809452] Dekany : index MIDI Note Number Frequency
2017-07-25 17:06:38.694 SatGam2[5476:1809452] 52 63 662.2421
2017-07-25 17:06:38.695 SatGam2[5476:1809452] 53 64 708.2311
2017-07-25 17:06:38.695 SatGam2[5476:1809452] 54 65 772.6157
2017-07-25 17:06:38.695 SatGam2[5476:1809452] 55 66 809.407
2017-07-25 17:06:38.695 SatGam2[5476:1809452] 56 67 882.9894
2017-07-25 17:06:38.695 SatGam2[5476:1809452] 57 68 910.5828
2017-07-25 17:06:38.696 SatGam2[5476:1809452] 58 69 993.3631
2017-07-25 17:06:38.696 SatGam2[5476:1809452] 59 70 1030.154
2017-07-25 17:06:38.696 SatGam2[5476:1809452] 60 73 1158.924
2017-07-25 17:06:38.696 SatGam2[5476:1809452] 61 74 1214.11
2017-07-25 17:06:38.697 SatGam2[5476:1809452]
(
"662.2421",
"708.2311",
"772.6157",
"809.407",
"882.9894",
"910.5828",
"993.3631",
"1030.154",
"1158.924",
"1214.11"
)
2017-07-25 17:06:38.697 SatGam2[5476:1809452] concert sequence for selectedFamily 1 and selectedPlayerID 1
2017-07-25 17:06:38.697 SatGam2[5476:1809452] entryPoints
2017-07-25 17:06:38.697 SatGam2[5476:1809452] 1 1 0 0
2017-07-25 17:06:38.698 SatGam2[5476:1809452] 2 1 0 0
2017-07-25 17:06:38.698 SatGam2[5476:1809452] 3 1 0 0
2017-07-25 17:06:38.698 SatGam2[5476:1809452] 4 1 0 0
2017-07-25 17:06:38.698 SatGam2[5476:1809452] 5 0 -1 48
2017-07-25 17:06:38.698 SatGam2[5476:1809452] 6 0 0 24
2017-07-25 17:06:38.699 SatGam2[5476:1809452] 7 1 1 0
2017-07-25 17:06:38.699 SatGam2[5476:1809452] 8 1 0 0
2017-07-25 17:06:38.699 SatGam2[5476:1809452] 9 0 -1 48
2017-07-25 17:06:38.699 SatGam2[5476:1809452] 10 0 0 24
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 11 1 1 0
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 12 1 0 0
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 13 1 0 0
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 14 0 -1 96
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 15 0 0 72
2017-07-25 17:06:38.700 SatGam2[5476:1809452] 16 0 0 48
2017-07-25 17:06:38.701 SatGam2[5476:1809452] 17 0 0 24
2017-07-25 17:06:38.701 SatGam2[5476:1809452] 18 1 1 0
2017-07-25 17:06:38.701 SatGam2[5476:1809452] 19 1 0 0
2017-07-25 17:06:38.701 SatGam2[5476:1809452] 20 1 0 0
2017-07-25 17:06:38.701 SatGam2[5476:1809452] 21 1 0 0
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 22 0 -1 144
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 23 0 0 120
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 24 0 0 96
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 25 0 0 72
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 26 0 0 48
2017-07-25 17:06:38.702 SatGam2[5476:1809452] 27 0 0 24
2017-07-25 17:06:38.703 SatGam2[5476:1809452] 28 1 1 0
2017-07-25 17:06:38.703 SatGam2[5476:1809452] 29 1 0 0
2017-07-25 17:06:38.703 SatGam2[5476:1809452] 30 0 -1 48
2017-07-25 17:06:38.703 SatGam2[5476:1809452] 31 0 0 24
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
frame #0: 0x03144383 libobjc.A.dylib`objc_release + 19
* frame #1: 0x00081c1c SatGam2`-[ConcertController startClock](self=0x786bb480, _cmd="startClock") at ConcertController.m:46 [opt]
frame #2: 0x00081b87 SatGam2`-[ConcertController initConcertStateMachine:forPlayer:](self=0x786bb480, _cmd="initConcertStateMachine:forPlayer:", selectedFamily=1, selectedPlayerID=1) at ConcertController.m:25 [opt]
frame #3: 0x00093a16 SatGam2`-[PlayViewController viewDidLoad](self=0x7aa49c00, _cmd="viewDidLoad") at PlayViewController.m:154 [opt]
frame #4: 0x014e2878 UIKit`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 38
frame #5: 0x014e7201 UIKit`-[UIViewController loadViewIfRequired] + 1434
frame #6: 0x014e776c UIKit`-[UIViewController view] + 29
frame #7: 0x00085c29 SatGam2`-[MultiviewViewController displayView:](self=<unavailable>, _cmd="displayView:", intNewView=<unavailable>) at MultiviewViewController.m:45 [opt]
frame #8: 0x000825ed SatGam2`-[MultiviewAppDelegate displayView:](self=0x793a1360, _cmd="displayView:", intNewView=4) at MultiviewAppDelegate.m:17 [opt]
frame #9: 0x0008828e SatGam2`-[SyncViewController fromSyncButton:](self=<unavailable>, _cmd="fromSyncButton:", button=0x7b67deb0) at SyncViewController.m:65 [opt]
frame #10: 0x03146220 libobjc.A.dylib`-[NSObject performSelector:withObject:withObject:] + 63
frame #11: 0x0131fca0 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 91
frame #12: 0x0131fc3a UIKit`-[UIApplication sendAction:toTarget:fromSender:forEvent:] + 41
frame #13: 0x014c7f67 UIKit`-[UIControl sendAction:to:forEvent:] + 64
frame #14: 0x014c82d1 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 469
frame #15: 0x014c7207 UIKit`-[UIControl touchesEnded:withEvent:] + 666
frame #16: 0x01396526 UIKit`-[UIWindow _sendTouchesForEvent:] + 3066
frame #17: 0x01397dea UIKit`-[UIWindow sendEvent:] + 4445
frame #18: 0x0133e1b0 UIKit`-[UIApplication sendEvent:] + 363
frame #19: 0x01bbac2f UIKit`__dispatchPreprocessedEventFromEventQueue + 2973
frame #20: 0x01bb20ff UIKit`__handleEventQueue + 1255
frame #21: 0x01bb3663 UIKit`__handleHIDEventFetcherDrain + 66
frame #22: 0x0360aa5f CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
frame #23: 0x035f01c4 CoreFoundation`__CFRunLoopDoSources0 + 500
frame #24: 0x035ef69c CoreFoundation`__CFRunLoopRun + 1084
frame #25: 0x035eefd4 CoreFoundation`CFRunLoopRunSpecific + 372
frame #26: 0x035eee4b CoreFoundation`CFRunLoopRunInMode + 123
frame #27: 0x0516aa7a GraphicsServices`GSEventRunModal + 71
frame #28: 0x0516a95f GraphicsServices`GSEventRun + 80
frame #29: 0x0131dbc9 UIKit`UIApplicationMain + 148
frame #30: 0x00080f74 SatGam2`main(argc=1, argv=0xbff82818) at main.m:12 [opt]
frame #31: 0x05f0e779 libdyld.dylib`start + 1
(lldb)
答案 0 :(得分:1)
我不完全确定是否是这样,但我认为你不应该在初始化程序中调用startClock
。该init方法通常不遵循合适的初始化器的正确结构,即
- (instancetype)init... {
self = [super init];
if (self) {
// initialize properties (and ivars in your case)
}
return self;
}
我认为问题在于您正在安排计时器,该计时器在初始化程序完成之前保存对self
的引用,即ConcertController
实例,即没有#t真的是self
。特别是因为你从未调用super
的初始值设定项(除非你在findEntryPointsFor:andPlayer:
方法中执行此操作,这完全取消了任何约定)。
如果您稍后再调用startClock
(例如从视图控制器),它可能已经有效,但我确实建议修复init
以满足约定。不要忘记,特别是在ARC下,不仅仅是编码美学,ARC还依赖于某些东西来恰当地推断出要保留和释放的内容等。
除此之外,您直接定义ivars的事实有点可疑。我想这来自MRC的迁移?我也建议在这里使用属性(这不是真正的性能损失,因为许多人似乎错误地相信)。唯一要记住的是,在初始值设定项中,您使用_ivarName
(即下划线表示法)访问它们,并依赖于其他地方的getter和setter(即通常的点语法,除了一些边缘情况,你需要避免一些键值观察的东西,但我从这里看到你甚至没有那个)。这真的是更清洁,更安全的方式,特别是当你想要更换计时器和所有这些时。如果您担心保持课程的公共界面清洁,请使用类扩展,这仍然比ivars更好。
答案 1 :(得分:0)
我的猜测是你的ConcertController声明不好。
试试PlayVC标题:
#import <UIKit/UIKit.h>
#import "ConcertController.h"
@interface PlayViewController : UIViewController
{
// remove this line.
}
@property (nonatomic, strong) ConcertController *concertStateMachine;
@end
如果它不是属性,则在需要内存时,iOS通常会自由释放该对象。在您的ConcertController中,您还应该更改NSTimer *计时器;也是财产。试一试。
答案 2 :(得分:-2)
如果您不使用ARC,
然后将其更改为:
lastEventChangeTime = [NSDate date];
尝试添加保留
lastEventChangeTime = [[NSDate date] retain];
完成lastEventChangeTime后,设置
lastEventChangeTime = nil;