Application
Mac OS X 与iOS 上的application 不太相同,在Mac OS X 上是NSApplication,在iOS 上则是UIApplication,但基本上都负责相同的工作:把来自外部的种种传递给内部,包括硬件事件,与其他各种系统事件。
硬件事件会被传递给window,而其他系统事件,像App被开启或关闭、被推到前景或背景、收到push notification…等等,则是会转发给application 的delegate。
由于application 位在responder chain 的最底层,每一个view 与window 都不处理的时候,才会丢给application 处理,所以如果我们希望处理一些会影响整个App 行为的事件的时候,就适合由application 这一层处理。
比方说,KKBOX是一个音乐App,所以我们会希望用户可以透过蓝芽耳机或线控耳机上的按钮,切换KKBOX当中的歌曲,换到前一首或下一首歌曲。在iOS 7.1之前,我们要处理线控耳机的事件,会选择实现UIResponder protocol中的-remoteControlReceivedWithEvent:
。因为换歌这件事情应该是对整个KKBOX的操作,无论放在哪个view或view controller都不适合,所以应该要放在application这一层。
要让application 这一层可以做额外的事情,我们首先要建立自己的UIApplication subclass:
@interface KKApplication : UIApplication
@end
然后,在main.m里头,告诉UIApplicationMain
,我们应该要使用KKApplication,而不是原本的UIApplication的实现:
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv,
NSStringFromClass([KKApplication class]),
NSStringFromClass([AppDelegate class]));
}
}
我们就可以在KKApplication 处理事件了:
@implementation KKApplication
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent
{
if (theEvent.type == UIEventTypeRemoteControl) {
switch(theEvent.subtype) {
case UIEventSubtypeRemoteControlPlay:
break;
case UIEventSubtypeRemoteControlPause:
break;
case UIEventSubtypeRemoteControlStop:
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
break;
case UIEventSubtypeRemoteControlNextTrack:
break;
case UIEventSubtypeRemoteControlPreviousTrack:
break;
...
default:
return;
}
}
}
@end
当然,如果我们想要开始接收来自耳机的事件,我们还要对UIApplication的singleton实例调用-beginReceivingRemoteControlEvents:
。
虽然跟application 这一层无关,不过提到了耳机线控,就得提一下。苹果在推出iOS 7.1 的时候,同时推出了Car Play 功能,Car Play 允许用户在车用音响的介面上控制iOS App,由于车用音响的画面较大,所以,除了可以用来切换前后首歌曲之外,苹果还加入了可以对歌曲评分,表示喜欢或不喜欢等功能,于是整个改写了处理耳机线控的这一块,推出MPRemoteCommandCenter 这个class。
从MPRemoteCommandCenter的singleton实例sharedCommandCenter
上,我们可以拿到许多种不同的MPRemoteCommand,然后对MPRemoteCommand设定target/action。我们之前想要开始播放,会在-remoteControlReceivedWithEvent:
里头处理UIEventSubtypeRemoteControlPlay,现在会改成向MPRemoteCommandCenter要求playCommand
,然后指定target/action,例如:
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(play:)];