iOS - Как сделать reloaddata таблицы в CfReadStream - PullRequest
2 голосов
/ 09 февраля 2012

Я новичок в iOS c, и теперь я создаю приложение, которое работает с FtpServer, чтобы получить список папок и поместить в UiTableView.

С этим кодом я работаю с потоком:

-(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 голосов
/ 14 февраля 2012

В этом случае ваши обратные вызовы сетевых событий будут приниматься асинхронно.Таким образом, в этом потоке, который отличается от основного потока, вы не можете вызвать [self.tableview reloadData] напрямую.

Если вы это сделаете, хотя reloadData, вероятно, будет выполняться, это непредсказуемо, когда.

Золотое правило заключается в том, что любая операция пользовательского интерфейса - или в этой связанной операции пользовательского интерфейса, то есть методчто где-то еще есть код, связанный с пользовательским интерфейсом - это должно быть сделано в главном потоке.

Поэтому решение заключается в том, что вам нужно сделать это:

    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...