3

背景

我的应用程序从网络流中提取数据,并更改屏幕上 UI 元素的值。一个元素是 UITextView,它用作传入数据的一种日志。只要应用程序收到具有传入数据性质的“HasBytesAvailable”NSStreamEvent,它就应该更新。(例如,如果传入的数据与蛋糕有关,则 textview 将更新为“6/22/12 8:00 - got cake”)下面显示了它如何更新的示例。

[logString insertString:@"This is an update\n" atIndex:0]; 
//logstring is a MutableString I use to hold my UITextView's text
[logString insertString:timeString atIndex:0]; //timestring is current time
logView.text = logString; //logView is my UITextView
[logView flashScrollIndicators];

//logstring and logview declaration and implementation
@property (nonatomic,retain) IBOutlet UITextView *logView;
@property (nonatomic,retain) NSMutableString *logString;

logString = [[NSMutableString alloc] initWithString:@"-logging started\n"];

问题

只要我不尝试滚动 TextView,更新就会按我的意愿进行。但是,如果我滚动浏览文本并按住它,大概足够长的时间让我的更新代码被调用,当我停止滚动时应用程序会崩溃。我可以很好地浏览文本,只是当它必须处理传入的数据包并且我仍在滚动时它会崩溃。此外,当我滚动时,没有其他内容会更新。应该由接收到的数据更新的所有标签保持不变。

我的想法

就好像应用程序无法同时处理滚动和处理传入数据一样。我不确定这是否是因为我在内存管理方面做错了,或者我需要覆盖一些滚动功能,或者完全是其他东西。任何帮助或想法表示赞赏。

解决方案

正如 trumpetlicks 所说,我需要为我的网络任务实现多线程来做到这一点,我做了以下工作:

在初始化中:

NSOperationQueue *networkQueue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(initNetworkCommunication) object:nil];
[networkQueue addOperation:operation];
[operation release];

在 initNetworkCommunication 中,初始化 CFSocketpair 和流之后:

[[NSRunLoop currentRunLoop] run]; //necessary to handle stream events
4

2 回答 2

0

从这里开始。

developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… 你可以

还希望添加您的网络设置和使用代码,以便我们都可以看到您在那里做什么!!!

于 2012-06-22T15:14:06.363 回答
0

我可以提出 3 个可以帮助您的想法:

1)不要从后台线程调用 UI 元素,总是在主线程上,例如使用:

   dispatch_async(dispatch_get_main_queue(), ^{

         self.textview.text = .....

    });

2)在线程之间使用某种同步(稍后会详细介绍..)

3) NSOperation 对于这个任务来说太复杂了,只需使用 NSURLSession 回调并在完成时调用一个必须序列化的“中央”方法(如 2 中所述)

假设在每个网络回调中:

...
    // create Session and request...
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                NSString * s = [[NSString alloc]initWithData:data encoding: NSUTF8StringEncoding];
                                                [self serializer:s];
                                            }
                                  ];
    [task resume];
...

4)现在让'尝试同步(并转到UI的主线程..)

在“init”/ViewDidLoad 创建一个

self.queue = dispatch_queue_create("com.acme.myQueue", DISPATCH_QUEUE_CONCURRENT);

5)在序列化方法中使用它:

-(void) serializer:(NSString*)s
{
    dispatch_barrier_async(self.queue, ^{
        [self updateUI:s];
    });
}

6) 更新用户界面:

-(void) updateUI:(NSString*)s
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString * currText = self.textView.text;
        self.textView.text = [NSString stringWithFormat:@"%@\n%@", currText, s];

    });
}

所以回顾一下我的所有控制器可以(一些细节留给你..)

@interface ViewController ()

@property dispatch_queue_t queue;
@property UITextView * textView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.queue = dispatch_queue_create("com.acme.myQueue", DISPATCH_QUEUE_CONCURRENT);

    [self startDownloadFromURL:@"https://www.apple.com"];
    [self startDownloadFromURL:@"https://www.google.com"];
}


-(void)startDownloadFromURL:(NSString*)urlString{

    NSURLSession * session;
    NSURLRequest * request;

    // create Session and request...
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                NSString * s = [[NSString alloc]initWithData:data encoding: NSUTF8StringEncoding];
                                                [self serializer:s];
                                            }
                                  ];
    [task resume];
}

-(void) serializer:(NSString*)s
{
    dispatch_barrier_async(self.queue, ^{
        [self updateUI:s];
    });
}


-(void) updateUI:(NSString*)s
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString * currText = self.textView.text;
        self.textView.text = [NSString stringWithFormat:@"%@\n%@", currText, s];

    });
}





@end
于 2017-08-19T20:47:16.700 回答