【问题标题】:Application's UI freezes when lots of stanzas are received收到大量节时应用程序的 UI 冻结
【发布时间】:2018-01-31 13:33:44
【问题描述】:

我正在使用 Robbiehanson 的 XMPPFramework 开发一个聊天应用程序,当我的应用程序收到很多节时,应用程序的 UI 冻结,这就是我制作我的流的方式。

当框架尝试针对收到的消息发送回执或流管理器尝试针对收到的节发送确认时,应用程序的 UI 大多会冻结。

这就是我设置直播的方式。

//流设置

if (!self.xmppStream || ![self.xmppStream isConnected]) {
    self.xmppStream = [[XMPPStream alloc] init];
     [self.xmppStream setHostName:kGetChatServerURLString];
    // [self.xmppStream setHostPort:kBPChatServerPort];

    [self.xmppStream setHostPort:kBPChatServerPort];
    [self.xmppStream setStartTLSPolicy:XMPPStreamStartTLSPolicyAllowed];
    self.xmppReconnect = [ [XMPPReconnect alloc] init];
    [self.xmppReconnect setAutoReconnect:YES];

    self.xmppRosterMemStorage = [[XMPPRosterMemoryStorage alloc] init];
    self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:self.xmppRosterMemStorage dispatchQueue:dispatch_get_main_queue()];

    self.xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = true;
    self.xmppRoster.autoFetchRoster = true;
    [self.xmppRoster activate:self.xmppStream];

    self.xmppMUC = [[XMPPMUC alloc] initWithDispatchQueue:_backgroundQueue];
    [self.xmppMUC activate:self.xmppStream];

    // To enable socket in the background.
    [self.xmppStream setEnableBackgroundingOnSocket:YES];

    // Moved the function to here from DidConnect to fix multiple delivery reports sending issue after reconnect.
    [self setupAutoSendDeliveryReceipts];

    XMPPMessageCarbons *xmppMessageCarbon  = [[XMPPMessageCarbons alloc] initWithDispatchQueue:_backgroundQueue];

    [xmppMessageCarbon activate:self.xmppStream];
    [xmppMessageCarbon setAutoEnableMessageCarbons:YES];

    //XEP-0191: Blocking Command
    self.xmppBlocking = [[XMPPBlocking alloc] initWithDispatchQueue:_backgroundQueue];
    [self.xmppBlocking activate:self.xmppStream];

    [self.xmppStream addDelegate:self delegateQueue:_backgroundQueue];
    [self.xmppReconnect addDelegate:self delegateQueue:_backgroundQueue];
    [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
    [self.xmppMUC addDelegate:self delegateQueue:_backgroundQueue];
    [self.xmppBlocking addDelegate:self delegateQueue:_backgroundQueue];

    [[BPCXMPPvCardStorageManager sharedInstance] activateWithStream:self.xmppStream];
    [[BPCChatRoomsManager sharedManager] activateWithStream:self.xmppStream];
}

//设置流管理器

- (void)setupStreamManagement {

if (kBPCTempEnableStreamManagement) {

    //Intialize with XMPPStreamManagementMemoryStorage
    XMPPStreamManagementMemoryStorage *xmppSMMS = [[XMPPStreamManagementMemoryStorage alloc] init];
    self.xmppStreamManagement = [[XMPPStreamManagement alloc] initWithStorage:xmppSMMS dispatchQueue:_backgroundQueue];

    //Activate with stream
    [self.xmppStreamManagement activate:self.xmppStream];
    self.xmppStreamManagement.autoResume = YES;
    [self.xmppStreamManagement enableStreamManagementWithResumption:YES maxTimeout:0];
    [self.xmppStreamManagement requestAck];
    [self.xmppStreamManagement sendAck];
    [self.xmppStreamManagement automaticallySendAcksAfterStanzaCount:1 orTimeout:0];
}
}

//启用自动消息传递

XMPPMessageDeliveryReceipts *xmppMessageDeliveryReceipts = [[XMPPMessageDeliveryReceipts alloc] initWithDispatchQueue:dispatch_queue_create("messageDeliverReceiptsQueue", DISPATCH_QUEUE_CONCURRENT)];
xmppMessageDeliveryReceipts.autoSendMessageDeliveryReceipts = YES;
xmppMessageDeliveryReceipts.autoSendMessageDeliveryRequests = YES;
[xmppMessageDeliveryReceipts activate:self.xmppStream];

我使用的后台队列是:

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

我该如何解决这个问题?

【问题讨论】:

  • 如果使用automaticallySendAcksAfterStanzaCount,则不需要sendAck

标签: ios objective-c sockets xmppframework


【解决方案1】:

如果 UI 冻结,其明确含义是您的某些工作正在主线程上进行。您必须寻找在主线程中运行的任务。然后在后台线程中编写这段代码,当它完成任务后切换到主线程来更新 UI。

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
    //Run UI Updates
});
});

【讨论】:

  • 主队列没有做任何事情,当框架尝试发送或接收节时,它会冻结 UI。
  • @ZeeshanAnjum 是什么让你如此轻易地忽略它?通常,冻结的 UI 是 指示主队列上的工作过多?我不知道 XMPPFramework,但肯定会在某些时候将数据交给主线程进行 UI 处理,对吧?我什至可以看到您在上面的代码中将委托队列设置为主队列。不幸的是,我无法给您答案,并且可以看出这个答案对您没有多大帮助,但是简单地否认显而易见的事情也对您没有帮助。至少解释一下你认为除了阻塞的主队列之外还有什么可以冻结 UI...
  • 这就是我想不通的,我所有的数据库操作都是在后台上下文中完成的,这显然不会阻塞 UI。我相信资源已经耗尽,由于哪个 UI 冻结?
【解决方案2】:

首先我会检查冻结期间主线程发生了什么。

  1. 通过 Xcode 在调试会话中运行应用程序。
  2. 当 UI 冻结时,单击调试工具栏中的“暂停”按钮。
  3. 检查主线程/(主队列线程)的调用堆栈。您应该看到导致冻结的函数以及调用它的人。

即使您确信您的代码在正确的队列/线程上运行,您使用的库也有可能显式分派到主队列。我以前也遇到过这种情况。

【讨论】:

    【解决方案3】:

    当您从框架中回调一些触发 UI 更新的数据时,您在哪个线程中执行?

    它必须是线程 1,因为 UIKit 只能在主线程上运行。如果不是主线程,则必须 dispatch_async(dispatch_get_main_queue(), ^block());并从块中调用 UIKit(又名所有 UI 调用)。我已经很难学会这一点,是的,用户界面变得非常缓慢并且行为非常奇怪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      • 1970-01-01
      • 2017-03-25
      • 2014-12-20
      • 1970-01-01
      相关资源
      最近更新 更多