我是iOS objective中的新手,现在我构建了一个与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];
}发布于 2012-02-14 11:20:54
在这种情况下,将异步接收网络事件回调。因此,在与主线程不同的线程上,不能直接调用[self.tableview reloadData]。
如果是这样的话,尽管reloadData可能会被执行,但在什么时候它是不可预测的。
金科玉律是,任何UI操作--或者在这个大小写UI相关操作中,即在其他地方有UI相关代码的方法--都必须在主线程上执行。
因此,解决方案是您需要这样做:
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];https://stackoverflow.com/questions/9213516
复制相似问题