iOS-如何在CfReadStream中制作tableview的reloaddata

时间:2012-02-09 15:15:56

标签: ios uitableview

我是iOS目标c的新手,现在我构建了一个与FtpServer一起使用的应用程序,用于检索文件夹列表并放入UiTableView。

使用此代码我使用stream:

-(void) readStream {

CFURLRef ftpURL=(CFURLRef)url;

CFReadStreamRef readFTPStream=CFReadStreamCreateWithFTPURL(kCFAllocatorDefault, ftpURL);
CFReadStreamSetProperty(readFTPStream,kCFStreamPropertyFTPUserName,userName);
CFReadStreamSetProperty(readFTPStream,kCFStreamPropertyFTPPassword,password);
CFReadStreamSetProperty (readFTPStream,kCFStreamPropertyFTPUsePassiveMode,NO);

MyStreamInfo streamInformation;
streamInformation.readStream=readFTPStream;


CFStreamClientContext clientContext={0,self,NULL,NULL,NULL};

CFOptionFlags events= kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred |    kCFStreamEventEndEncountered;



BOOL flagOpen=CFReadStreamSetClient(readFTPStream, events,(void*)didStartReceiveList, &clientContext);


if (flagOpen) {


    CFReadStreamScheduleWithRunLoop(readFTPStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    //CFReadStreamUnscheduleFromRunLoop(readFTPStream, CFRunLoopGetCurrent(), kCFRunLoopRunFinished);

}


if(!CFReadStreamOpen(readFTPStream)){
    NSLog(@"Could not open read stream");
}

NSLog(@"fine");

}

所以我是回调事件的callbackFunction:

void didStartReceiveList(NSInputStream *stream,CFStreamEventTypeevent,CFStreamClientContext *clientContext) {


   //ViewController *self = (__bridge_transfer ViewController *)clientContext;


    ViewController *self=( ViewController *)clientContext;

switch(event) {
    case kCFStreamEventHasBytesAvailable:{

        [self readStreamData:(CFReadStreamRef)stream :clientContext];

    }
        break;
    case kCFStreamEventErrorOccurred: {

        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"iFTP" 
                                                      message:[self message]
                                                     delegate:self 
                                            cancelButtonTitle:@"OK" 
                                            otherButtonTitles:nil];
        [alert show];

    }

        break;
    case kCFStreamEventEndEncountered:{
        //reload data

         **here in the reload i receive Signal crash**

        [self.tb reloadData];




    }
        break;
    }

}

,这是流方法

-(void) readStreamData:(CFReadStreamRef) stream :(CFStreamClientContext*)  context {


MyStreamInfo *info=context->info;    
int offset=0;

CFIndex bytesRead = CFReadStreamRead(stream, info->buffer + offset,kMyBufferSize-offset);

if (bytesRead < 0) {

    CFErrorRef err=CFReadStreamCopyError(stream);
    CFStringRef str=CFErrorCopyDescription(err);
    NSString *descr=(__bridge_transfer NSString *)str;

    self.message=[NSString stringWithString:descr];
    fprintf(stderr, "CFReadStreamRead returned %ld: %s.", bytesRead,strerror(errno));
    CFRelease(err);

} else if (bytesRead == 0) {



    self.message=[[NSString alloc ]initWithString:@"Nothing to read"];
    fprintf(stderr, "CFReadStreamRead returned %ld: %s.", bytesRead,strerror(errno));
    //CFReadStreamClose(stream);


}

int bufSize = bytesRead + offset;
int totalBytesRead=0;
totalBytesRead+= bufSize;

int totalBytesConsumed=0;
CFIndex bytesReturned;

const UInt8 *newBuffer=info->buffer+totalBytesConsumed;
NSDictionary *d=[[NSDictionary alloc]init];
if (bytesRead>0) {

    do {
        const UInt8 *buffRemaining=info->buffer+totalBytesConsumed;
        NSDictionary *dict=[[NSDictionary alloc] init];
        CFDictionaryRef dictionaryParsed=(__bridge_retained CFDictionaryRef)dict;
        bytesReturned=CFFTPCreateParsedResourceListing(NULL, newBuffer, bufSize, &dictionaryParsed);

        if (bytesReturned>0) {
            if (dictionaryParsed!=NULL) {

                d=(__bridge_transfer NSDictionary *)dictionaryParsed;
                NSString *name=[d valueForKey:(NSString *)kCFFTPResourceName];
                [self.listEntries addObject:name];


            }


            totalBytesConsumed += bytesReturned;
            bufSize -= bytesReturned;
            info->leftOverByteCount = bufSize; 
    ;        newBuffer=info->buffer+totalBytesConsumed;

        } 
        else if (bytesReturned == 0) {

            info->leftOverByteCount = bufSize;
            totalBytesRead -= info->leftOverByteCount;
            memmove(info->buffer, buffRemaining, info->leftOverByteCount);
        } 

        else if (bytesReturned == -1) {
            alert=[[UIAlertView alloc] initWithTitle:@"iFTP" 
                                             message:@"CFFTPCreateParsedResourceListing parse failure" 
                                            delegate:self 
                                   cancelButtonTitle:@"OK" 
                                   otherButtonTitles:nil];
            [alert show];
            break;
        }

    } while (bytesReturned>0 );

    //self.tb.delegate=self;
    //Add new records to the table
    //ViewController *self = (ViewController *)context;


    //[self.tb beginUpdates];
    NSMutableArray *iPath=[[NSMutableArray alloc] init];

    for (int i=0; i<[listEntries count]; i++) {
        NSIndexPath *iP=[NSIndexPath indexPathForRow:i inSection:0];
        [iPath addObject:iP];
    }



}

}

代码工作正常,当在事件结束时的didreceiveStart回调中我决定重新加载我的表视图的数据。 我不知道为什么我不能在那一点上使用self.tableview重载数据 有人能帮我吗? 感谢的

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tb dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault    reuseIdentifier:CellIdentifier] autorelease];
}

@try {
    cell.textLabel.text=[listEntries objectAtIndex:indexPath.row];
}
@catch (NSException *exception) {
    NSLog(@"%@",exception.reason);
}
@finally {
    NSLog(@"%@",cell.textLabel.text);

}

cell.textLabel.textColor=[UIColor blackColor];

CGFloat r=255;
CGFloat g=140;
CGFloat b=0;


cell.backgroundColor=[UIColor colorWithRed:r green:g blue:b alpha:1.0];
return cell;

}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

NSLog(@"%d",[listEntries count]);
return [listEntries count];
}

1 个答案:

答案 0 :(得分:0)

在这种情况下,您的网络事件回调将以异步方式接收。因此,在该线程上 - 与主线程不同 - 您无法直接调用[self.tableview reloadData]

如果你这样做,虽然reloadData可能会被执行,但是时间不可预测。

黄金法则是任何UI操作 - 或者在这个与套管相关的UI操作中,即其他地方都有UI相关代码的方法 - 必须在主线程上完成。

因此,解决方案是你需要这样做:

    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];