UITextView滚动后应用程序崩溃

时间:2012-06-22 13:59:31

标签: iphone ios networking crash uitextview

背景

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

[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];
初始化CFSocketpair和流后,在initNetworkCommunication中

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

2 个答案:

答案 0 :(得分:0)

从这里开始。

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

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

答案 1 :(得分:0)

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

1)DONT从后台线程调用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)更新UI:

-(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