为什么我的线程在 iOS 上启动几个线程后似乎失败了?

2023-12-20

我有这个代码- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath代表电话:

dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[webUrls objectAtIndex:indexPath.row]];
    CMTime timeduration = playerItem.duration;
    float seconds = CMTimeGetSeconds(timeduration);
    NSString *duration = [NSString stringWithFormat:@"%f", seconds];

    dispatch_async( dispatch_get_main_queue(), ^{

        UITableViewCell *updatecell = [tblView cellForRowAtIndexPath:indexPath];
        updatecell.detailTextLabel.text = duration;
        [updatecell setNeedsLayout];
    });
});

每个单元在后台缓慢地加载seconds进入updatecell.detailTextLabel.text在细胞上。问题是在我滚动后,加载大约 3 或 4 个单元格后,其余的单元格很快就会在细节文本标签中显示 0 并且不会加载。

有什么想法吗?我的线程处理不正确吗?


有几点想法:

  1. 许多服务器对它们从给定客户端接受的并发请求数量施加限制。我建议你使用NSOperationQueue将向服务器发出的并发请求数量限制为 4 或 5,而不是使用调度队列。

  2. 您可能会使问题变得比需要的更糟糕,因为如果您向下滚动表格视图然后向后滚动,当您重新显示前几个单元格时,您将重新下载AVPlayerItem并尝试向您的服务器发出额外的并发请求。您确实应该保存以前下载的结果,以避免对相同数据进行冗余的重新请求。

  3. 在尝试更新 UI 之前,您当前不会检查刚刚下载的单元格是否仍然可见。你真的应该检查一下。

因此,我可能会提出以下建议:

  1. 在你的视图控制器中viewDidLoad,创建NSOperationQueue我们将用于下载。还指定您的服务器允许的并发操作数:

    downloadQueue = [[NSOperationQueue alloc] init];
    downloadQueue.maxConcurrentOperationCount = 4; // replace this with an appropriate value for your server
    
  2. 之前,你有一个数组,webUrls,这是一个数组NSURL对象。在下面的第 4 点中,我们将讨论停用该数组,并创建一个新的行对象数组。但在我们做到这一点之前,我们应该创建这个新的RowData object.

    每个行对象不仅有webURL,还有其他东西,例如durationText甚至也许AVPlayerItem本身。 (通过保留这些其他对象属性,当单元格滚动回到视图中时,我们不需要重新下载数据。)因此这个新类的公共接口可能如下所示:

    //
    //  RowData.h
    //
    
    #import <Foundation/Foundation.h>
    
    @class AVPlayerItem;
    
    @interface RowData : NSObject
    
    @property (nonatomic, strong) NSURL *webURL;
    @property (nonatomic, strong) NSString *durationText;
    @property (nonatomic, strong) AVPlayerItem *playerItem;
    @property (nonatomic, getter = isDownloaded, readonly) BOOL downloaded;
    @property (nonatomic, getter = isDownloading, readonly) BOOL downloading;
    
    - (void)downloadInQueue:(NSOperationQueue *)queue completion:(void (^)(BOOL success))block;
    - (void)cancelDownload;
    
    @end
    

    顺便说一句,我并不热衷于班级名称,RowData。有点太暧昧了。但我对模型数据的性质了解不够,无法提出更好的名称。请随意为该类命名任何您认为合适的名称。

  3. 你的新RowData类可以有一个实例方法,称为downloadInQueue,执行下载,设置durationText通过将下载逻辑移至此处,我们成功地隔离了cellForRowAtIndexPath从一些涉及下载的血腥细节。但同样重要的是,这downloadInQueue方法不会更新用户界面本身,但它有completion块提供者cellForRowAtIndexPath(在下面的第 5 点中进行了演示),所以这downloadInQueue方法不必担心 UI 方面的考虑。无论如何,实施downloadInQueue可能看起来像:

    //
    //  RowData.m
    //
    
    #import "RowData.h"
    #import <AVFoundation/AVFoundation.h>
    
    @interface RowData ()
    
    @property (nonatomic, getter = isDownloaded) BOOL downloaded;
    @property (nonatomic, getter = isDownloading) BOOL downloading;
    @property (nonatomic, weak) NSOperation *operation;
    
    @end
    
    @implementation RowData
    
    - (void)downloadInQueue:(NSOperationQueue *)queue completion:(void (^)(BOOL success))completion
    {
        if (!self.isDownloading)
        {
            self.downloading = YES;
    
            NSOperation *currentOperation = [NSBlockOperation blockOperationWithBlock:^{
                BOOL success = NO;
    
                self.playerItem = [AVPlayerItem playerItemWithURL:self.webURL];
                if (self.playerItem)
                {
                    success = YES;
                    CMTime timeduration = self.playerItem.duration;
                    float seconds = CMTimeGetSeconds(timeduration);
                    self.durationText = [NSString stringWithFormat:@"%f", seconds];
                }
                self.downloading = NO;
                self.downloaded = YES;
    
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    completion(success);
                }];
            }];
    
            [queue addOperation:currentOperation];
            self.operation = currentOperation;
        }
    }
    
    - (void)cancelDownload
    {
        if ([self isDownloading] && self.operation)
        {
            self.downloading = NO;
            [self.operation cancel];
        }
    }
    
    @end
    
  4. 在您的主视图控制器中,而不是创建旧的数组webUrls,创建一个新数组RowData称为的对象,例如objects。设置webURL每个人的财产RowData当然是物体。 (再说一次,我对这个含糊不清的名字并不疯狂objects,但我对您的应用了解不够,无法提出更具体的建议。随便你怎么称呼它。但我下面的代码将使用objects.)

  5. 最后,修改你的cellForRowAtIndexPath使用这个新的RowData对象,它是downloadInQueue方法。另外,请注意,completion块检查以确保单元格仍然可见:

    RowData *rowData = self.objects[indexPath.row];
    
    if ([rowData isDownloaded])
    {
        cell.detailTextLabel.text = rowData.durationText;
    }
    else
    {
        cell.detailTextLabel.text = @"..."; // you really should initialize this so we show something during download or remove anything previously there
    
        [rowData downloadInQueue:self.downloadQueue completion:^(BOOL success) {
            // note, if you wanted to change your behavior based upon whether the 
            // download was successful or not, just use the `success` variable
    
            UITableViewCell *updateCell = [tblView cellForRowAtIndexPath:indexPath];
    
            // by the way, make sure the cell is still on screen
    
            if (updateCell)
            {
                updateCell.detailTextLabel.text = rowData.durationText;
                [updateCell setNeedsLayout];
            }
        }];
    }
    
  6. 如果使用 iOS 6,如果您想在单元格滚出屏幕时取消挂起的下载,您可以使用didEndDisplayingCell的方法UITableViewDelegate协议。

    - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        RowData *rowData = self.objects[indexPath.row];
    
        if ([rowData isDownloading])
            [rowData cancelDownload];
    }
    

    如果支持早期版本的 iOS,您必须使用UIScrollViewDelegate协议方法,例如scrollViewDidScroll http://developer.apple.com/library/ios/documentation/uikit/reference/uiscrollviewdelegate_protocol/Reference/UIScrollViewDelegate.html#//apple_ref/occ/intfm/UIScrollViewDelegate/scrollViewDidScroll%3a,确定哪些单元格已滚出屏幕(例如,不包含在indexPathsForVisibleRows)手动,但想法是一样的。

顺便说一句,在我的样本中RowData上面,我正在保存AVPlayerItem。仅当您需要时才应该这样做AVPlayerItem之后。我们已经保存了duration,这实现了我们所需要的一切UITableViewCell,但我假设您稍后可能想要对AVPlayerItem,所以我也保存它。但如果你不需要那个AVPlayerItem稍后,然后不要将其保存在RowData目的。另外,我不知道它们有多大,但你可能想写一个didReceiveMemoryWarning这将迭代你的objects并设置每个项目的playerItem反对nil.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的线程在 iOS 上启动几个线程后似乎失败了? 的相关文章

  • 打乱 NSMutableArray 而不重复并显示在 UIButton 中

    在我看来 我有 12 个按钮 一个数组包含 6 个名称 我想在其中打印数组名称UIButton标题 这是我的代码 texts NSMutableArray alloc initWithObjects 1 2 3 4 5 6 nil UIBu
  • 如何替换已弃用的方法dispatch_get_current_queue()? [复制]

    这个问题在这里已经有答案了 我正在 iOS 5 中使用 xmppframework 开发一个聊天应用程序 它工作得很好 但我将 Xcode 更新到 4 5 1 将 iOS 5 更新到 iOS 6 将 Mac OS 更新到 10 7 5 但由
  • 使用 iPhone 中的地图视图读取当前位置名称

    我读取了当前位置的纬度和经度值 然后成功将该位置固定在 iPhone 中 现在我想使用这个纬度和经度值读取该地名 我使用以下代码来读取查找当前位置 void mapView MKMapView mapView1 didUpdateUserL
  • 在横向中自动调整 UITableCells 内容的大小

    在 UITableView 中 我通过 UILabels 将内容添加到单元格中 定义最佳尺寸 与单元格宽度允许的一样大 我注意到只有tableView contentSize width是可靠的 因为cell contentView bou
  • 是否可以使用 Firebase 安排推送通知? [复制]

    这个问题在这里已经有答案了 我已经阅读了我能找到的所有文档 但仍然不知道这是否可行 如果我是用户 我可以安排特定时间的推送通知吗 Example 1 我是用户并打开应用程序 2 我允许通知并转到 pickerView 或其他任何内容 并设置
  • 在 Xcode 5 中重命名 iOS 项目[重复]

    这个问题在这里已经有答案了 我需要重命名一个 iOS 项目 有没有办法在不开始一个全新项目的情况下做到这一点 我发现的所有其他信息都与 Xcode 4 或旧版本相关 这些方法似乎使项目崩溃 我在尝试任何名称更改之前创建了一个快照 在 Xco
  • UIButton的高亮状态由什么控制事件开始和结束

    我正在创建类似钢琴的视图UIButton作为钢琴键 什么UIControlEvents当按钮获得和失去突出显示状态时 我应该监听以获得回调吗 我试图创建子类UIButton并添加属性观察者highlighted并且运行良好 然而 有时我需要
  • 覆盖层不与 UITableView 一起滚动 - iOS

    我有一个 UITableView 类 它使用以下方法在转到下一个屏幕时调用加载覆盖 问题是这个加载屏幕不随列表滚动 所以如果你滚动一点并单击某些东西 加载屏幕不会显示 因为它位于顶部 如何让加载屏幕始终保持在 UITableView 的顶部
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 忽略触摸事件,让其下面的视图处理触摸?

    我有一个用户可以触摸的可拖动视图 但它的某些矩形将没有图像 alpha 0 当用户单击透明区域时 我能够在没有 alpha 信息的情况下构造透明区域 我希望透明区域下方的视图 同一类 来检测触摸 我的策略是当用户触摸透明区域时让视图忽略触摸
  • 将 Firebase 云消息传递与 Windows 应用程序结合使用

    我在 Android 和 iOS 应用程序中使用 Firebase Cloud Messaging 但是我还有此应用程序的 Windows Mac OS 版本 我想保留相同的逻辑 我知道 Firebase Cloud Messaging 可
  • 推送动画,没有阴影和停电

    我有一个简单的iOS NavigationController基于应用程序 二UICollectionViews 相继 如果元素打开 第一个合集 被点击时 第二集 将被打开 非常简单 重要的提示 Both UICollectionViews
  • ios水平居中约束问题?

    I am having hard time in learning constraints auto layout in iOS I have used any width any height I have a storyboard sc
  • 如何让按钮闪烁?

    我试图在扫描正确时将按钮的颜色 只是闪烁 闪烁 更改为绿色 在出现问题时将按钮的颜色更改为红色 我可以用这样的视图来做到这一点 func flashBG UIView animateWithDuration 0 7 animations s
  • 在 iPhone 中缝合图片

    我想并排缝合2张png 在Cocoa中 我会使用 NSImage initWithSize 然后只是drawInRect 但是 UIImage 没有 initWithSize 类 我现在该怎么做 Use UIGraphicsBeginIma
  • 如何将 ios7 通用应用程序升级到基于 Xcode 6 的通用故事板应用程序?

    我目前有一个基于 xcode 5 ios 7 的通用应用程序 因此有两个故事板 我正在考虑将其更新到 ios 8 有没有办法 最佳方法将两个故事板迁移到通用的单个故事板 我在 xcode 6 中看不到转换选项 None
  • PFQueryTableViewController 错误

    我正在遵循在线教程 使用 Parse 作为后端创建照片共享应用程序 我已经运行了两次教程 两次都从头开始创建应用程序 但在同一位置仍然出现相同的错误 我到处寻找解决方案 但仍然没有运气 我正在使用 PFQueryTableViewContr
  • Swift 中的 import 语句是否有相关成本?

    阅读字符串宣言 我看到一个段落 https github com apple swift blob master docs StringManifesto md batteries included关于避免Foundation不需要的时候导
  • Xcode 8 / Swift 3:“UIViewController 类型的表达式?未使用”警告

    我有以下函数 它之前编译得很干净 但在 Xcode 8 中生成警告 func exitViewController navigationController popViewController animated true UIViewCon
  • 在发生更改事件时将货币格式重新应用到 UITextField

    我正在使用一个包含本地化货币值的 UITextField 我看过很多关于如何使用此功能的帖子 但我的问题是 如何在每次按键后将货币格式重新应用到 UITextField 我知道我可以通过以下方式设置和使用货币格式化程序 NSNumberFo

随机推荐

  • 自动输入 Python 提示

    我正在尝试编写一个 python 脚本 它将为我执行 bash 命令行程序 该程序要求用户输入两次 我希望我的脚本每次都自动输入 1 我听说过这样的事情 os system program lt prepared input 如何编写pre
  • q-learning计算中的大量状态

    我通过 q learning 实现了一款 3x3 OX 游戏 它在 AI vs AI 和 AI vs Human 中完美运行 但我无法更进一步地进行 4x4 OX 游戏 因为它会耗尽我所有的 PC 内存并崩溃 这是我当前的问题 大数组中的访
  • 根据优先级映射数据框列

    我有一个主数据框 main df 例如 A B X Y Id1 0 cat cat1 catabc 0 1 uuid01 1 cat cat1 catxyz 0 4 uuid02 2 cat cat2 catpqr 0 5 uuid01 3
  • Javascript - 按日期然后按时间对对象数组进行排序

    我有以下数组 id 1 value value1 date 2018 08 08 time 15 27 17 id 2 value value2 date 2018 08 09 time 12 27 17 id 3 value value3
  • 在 R 中创建水平条形图以显示活动序列

    数据集 患者 是患者访问诊所并接受治疗的事件日志 下面的脚本提供了一个数据帧 其中包含事件日志中的跟踪或活动序列 trace id 以及特定跟踪之后的案例的绝对频率 我希望使用创建动态水平条形图ggplot2 or plotly这样 迹线的
  • JPA和独特的领域

    我的应用程序中有两个持久性对象 事物和附加到事物的标签 该应用程序可以生成带有附加标签的事物集合 标签对象具有唯一的名称 使用相同标签两次标记某物是没有意义的 插入事物 附加标签对象 时 其中一些具有相同名称的标签对象可能已存在于数据库中
  • 是否可以声明具有无限上限的 Ada 范围?

    我想在 Ada 中声明记录类型的速度范围 下面的方法行不通 但是有没有办法让它工作呢 Speed in knots range 0 to unlimited Speed float Range 0 0 unlimited 我只想要这个数字的
  • 如何从加密字符串中提取加密方法生成的IV向量

    我在提取使用 生成的 IV 时遇到问题encrypt方法来自encrypted strings我提供的特定密码库 从文档中 我看到此方法使用 C 库根据密码生成密钥和 iv 该 C 库调用与 openssl 相同的方法来生成密钥和 iv E
  • AWS ElasticBeanstalk .ebextensions 未执行

    我正在尝试在 AWS EB 上部署后完成一些事情 我已经添加了我的 ebextensions到 git 存储库 我只有一个文件01 container commands config 当我跟踪时它似乎没有运行 var log eb acti
  • Google Firestore - 构建深度嵌套的有序数据

    我正在尝试弄清楚如何使用 Cloud Firestore 构建我的锻炼应用程序的数据 数据模型如下 该应用程序有很多组练习 每组练习都有一个有序的练习列表 每个练习都有一个练习部分的有序列表 每个练习部分都有一个有序的说明列表 每条指令都有
  • 为什么要池化无状态会话 Bean?

    Java 中的无状态 bean 不会在客户端的两次调用之间保留其状态 简而言之 我们可以将它们视为具有业务方法的对象 每个方法都接受参数并返回结果 调用该方法时 会在执行堆栈中创建一些局部变量 当该方法返回时 局部变量将从堆栈中删除 并且如
  • 正则表达式匹配特定位置的字符

    我需要想出一个正则表达式来仅查找给定文本位置 9 上的字母 A F 或 E 我对正则表达式非常陌生 做了一些搜索 但找不到任何类似的响应 到目前为止我所拥有的是 9 A 该命令似乎可以在空格九上找到字母 A 但如何将其他 2 个字母添加到正
  • 使用 ImageSharp 将 Image 转换为 Byte[]

    如何使用 ImageSharp 库将图像转换为字节数组 ImageSharp 库还可以建议 提供基于 EXIF 方向的 RotateMode 和 FlipMode 吗 如果您想将原始像素转换为byte 您执行以下操作 var bytes i
  • 如何在 Angular 中不返回数据的 http.post 请求上使用“toPromise()”?

    我最近开始学习 Angular 4 并遵循 Angular io 的教程 但现在我正在尝试构建自己的应用程序 但遇到了一些问题 我花了一整天的时间试图解决这个问题 但我失败了 我正在开发一个目前只有登录和注销功能的身份验证服务 The lo
  • “如果不存在则创建表” - 如何检查架构?

    是否有 或多或少 标准方法不仅检查名为mytable存在 而且其架构是否与应有的相似 我正在尝试H2数据库 http www h2database com and CREATE TABLE IF NOT EXISTS mytable 语句显
  • 如何从字符串中获取字符数组?

    在 JavaScript 中如何将字符串转换为字符数组 我想得到一个像这样的字符串 Hello world 到数组 H e l l o w o r l d 注意 这不兼容 unicode I U split 结果在 4个字符数组 I u 这
  • 包含仅具有静态方法的类的模块

    我有一个包含许多类的 Python 模块 每个类代表一种特定的物理材料及其属性 例如密度 比热 有些属性只是float该类的成员 但许多取决于某些参数 例如温度 我通过实现这个 staticmethods 即所有的类看起来像 class C
  • 使用 Tkinter 命令“iconbitmap”设置窗口图标

    我有一个带有 Tkinter 窗口的程序 我想为该窗口设置一个图标 我使用这段代码 window iconbitmap os path dirname os path abspath file icon png 但抛出以下错误 Traceb
  • 一起使用 javascript 和 php 进行验证

    如何同时使用 php 和 javascript 从我自己的研究来看 这似乎是不可能的 我知道他们是不同的 他们每个人都有自己独特的事情 但假设您正在验证表单 您使用 javascript 验证表单 然后如果没有错误 则运行 php 插入一条
  • 为什么我的线程在 iOS 上启动几个线程后似乎失败了?

    我有这个代码 UITableViewCell tableView UITableView tableView cellForRowAtIndexPath NSIndexPath indexPath代表电话 dispatch async di