我是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];
}
答案 0 :(得分:0)
在这种情况下,您的网络事件回调将以异步方式接收。因此,在该线程上 - 与主线程不同 - 您无法直接调用[self.tableview reloadData]
。
如果你这样做,虽然reloadData
可能会被执行,但是时间不可预测。
黄金法则是任何UI操作 - 或者在这个与套管相关的UI操作中,即其他地方都有UI相关代码的方法 - 必须在主线程上完成。
因此,解决方案是你需要这样做:
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];