使用 MPMusicPlayerController 的性能问题 - 可以在后台访问它吗?

发布于 2024-12-31 21:26:26 字数 3148 浏览 4 评论 0原文

编辑:用几个月后我找到的答案更新我自己的问题。简短的回答是否定的,MPMusicPlayerController 将所有调用转发到主线程。但它使用 CPDistributedMessagingCenter 来实际处理所有操作,因此可以非常轻松地编写一个替换控制器来进行异步调用(但据我所知,它不适用于沙盒 App Store 应用程序) - 如果确实如此,苹果将立即拒绝)。

我正在制作一个简单的应用程序来控制 iPod 播放,因此我一直在使用 MPMusicPlayerController,Apple 规定它只能在主线程中使用。然而,我在用户界面中遇到了一些令人沮丧的性能问题。切换到下一首或上一首歌曲是通过滑动触发的,滑动会移动整个显示(歌曲信息),然后在触发切换时更新下一首歌曲的显示。问题是,一旦歌曲被更改,当从 MPMusicPlayerController 检索歌曲信息时,UI 会挂起长达一秒钟。我已经尝试了我能想到的所有方法来优化代码,但在我看来,修复它的唯一方法是将 MPMusicPlayerController 代码移动到后台线程,尽管苹果的指示没有到。

更新显示的代码,供参考:

// Called when MPMusicPlayerControllerNowPlayingItemDidChangeNotification is received
- (void) nowPlayingDidChange {
    if ([iPodMusicPlayer nowPlayingItem]) {
        // Temp variables (necessary when updating the subview values in the background)
        title = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyTitle];
        artist = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyArtist];
        album = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyAlbumTitle];
        artwork = [[[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyArtwork] imageWithSize:CGSizeMake(VIEW_HEIGHT - (2*MARGINS), VIEW_HEIGHT - (2*MARGINS))];
        length = [[[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyPlaybackDuration] doubleValue];
        if (updateViewInBackground)
            [self performSelectorInBackground:@selector(updateSongInfo) withObject:nil];
        else
            [self updateSongInfo];
    }
    else
        [self setSongInfoAsDefault];
}

- (void) updateSongInfo {
    // Subviews of the UIScrollView that has performance issues
    songTitle.text = title;
    songArtist.text = artist;
    songAlbum.text = album;
    songLength.text = [self formatSongLength:length];

    if (!artwork) {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.00)
            songArtwork.image = [UIImage imageWithContentsOfFile:
                             @"/System/Library/Frameworks/MediaPlayer.framework/[email protected]"];
        else
            songArtwork.image = [UIImage imageWithContentsOfFile:
                                 @"/System/Library/Frameworks/MediaPlayer.framework/noartplaceholder.png"];
    }
    else
        songArtwork.image = artwork;

    title = nil;
    artist = nil;
    album = nil;
    artwork = nil;
    length = 0.0;
}

这里有什么我遗漏的吗(即更新 UIScrollView 子视图时的性能优化)?如果不是,那么在后台线程中使用 MPMusicPlayerController 会是一个坏主意吗?我知道如果其他东西正在访问 iPodMusicPlayerMPMusicPlayerController 中的 iPod 共享实例),这可能会导致问题,但是有什么方法可以解决这个问题吗?

另外,这是一个越狱调整(通知中心小部件),因此我可以利用 Apple 的私有框架,如果它们比 MPMusicPlayerController 类(无论如何它相当有限)工作得更好,我的目的。不过,这也意味着我的应用程序将作为 SpringBoard 进程的一部分运行,因此我想确保我的代码尽可能安全和稳定(每当我的代码出错时,我都会遇到 2 分钟的挂起,这我不希望在我发布此内容时发生这种情况)。因此,如果您有任何建议,我将非常感激!如果需要,我可以提供更多代码/信息。谢谢!

EDIT: Updating my own question with the answer I figured out months later. Short answer is no, MPMusicPlayerController forwards all calls to the main thread. But it uses a CPDistributedMessagingCenter to actually handle all operations, so one can very easily write a replacement controller that makes asynchronous calls (but it won't work for a sandboxed App Store app, as far as I know - and if it did, Apple would promptly reject it).

I'm making a simple app to control iPod playback, so I've been using an MPMusicPlayerController, which Apple states can only be used in the main thread. However, I've been experiencing some frustrating performance issues in the UI. Switching to the next or previous song is triggered by a swipe, which moves the entire display (of the song info) with it, and then updates the display for the next song when the switch is triggered. The trouble is that once the song has been changed, the UI hangs for up to a second while the song info is retrieved from the MPMusicPlayerController. I've tried most everything I can think of to optimize the code, but it seems to me that the only way to fix it is to move the MPMusicPlayerController code on to a background thread, despite Apple's instructions not to.

The code to update the display, for reference:

// Called when MPMusicPlayerControllerNowPlayingItemDidChangeNotification is received
- (void) nowPlayingDidChange {
    if ([iPodMusicPlayer nowPlayingItem]) {
        // Temp variables (necessary when updating the subview values in the background)
        title = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyTitle];
        artist = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyArtist];
        album = [[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyAlbumTitle];
        artwork = [[[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyArtwork] imageWithSize:CGSizeMake(VIEW_HEIGHT - (2*MARGINS), VIEW_HEIGHT - (2*MARGINS))];
        length = [[[iPodMusicPlayer nowPlayingItem] valueForProperty:MPMediaItemPropertyPlaybackDuration] doubleValue];
        if (updateViewInBackground)
            [self performSelectorInBackground:@selector(updateSongInfo) withObject:nil];
        else
            [self updateSongInfo];
    }
    else
        [self setSongInfoAsDefault];
}

- (void) updateSongInfo {
    // Subviews of the UIScrollView that has performance issues
    songTitle.text = title;
    songArtist.text = artist;
    songAlbum.text = album;
    songLength.text = [self formatSongLength:length];

    if (!artwork) {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.00)
            songArtwork.image = [UIImage imageWithContentsOfFile:
                             @"/System/Library/Frameworks/MediaPlayer.framework/[email protected]"];
        else
            songArtwork.image = [UIImage imageWithContentsOfFile:
                                 @"/System/Library/Frameworks/MediaPlayer.framework/noartplaceholder.png"];
    }
    else
        songArtwork.image = artwork;

    title = nil;
    artist = nil;
    album = nil;
    artwork = nil;
    length = 0.0;
}

Is there anything I'm missing here (ie. performance optimization when updating the UIScrollView subviews)? And if not, would it be such a bad idea to just use the MPMusicPlayerController in a background thread? I know that can lead to issues if something else is accessing the iPodMusicPlayer (shared instance of the iPod in MPMusicPlayerController), but are there any ways I could potentially work around that?

Also, this is a jailbreak tweak (a Notification Center widget), so I can make use of Apple's private frameworks if they would work better than, say, the MPMusicPlayerController class (which is fairly limited anyways) for my purposes. That also means, though, that my app will be running as a part of the SpringBoard process, so I want to be sure that my code is as safe and stable as possible (I experience 2 minute hangs whenever my code does something wrong, which I don't want happening when I release this). So if you have any suggestions, I'd really appreciate it! I can provide more code / info if necessary. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文