这是我第一次尝试编写自己的代表。我正在使用iOS5 Beta 7并编写我的委托功能。
它应该做的是表(MyTableController
)加载电视频道列表。这是一个包含键“logotype”的字典,它是图像标识的URL。
我创建了名为“Channel
”的班级,我的代表名为“ChannelDelegate
”。现在,当我的表cellForRowAtIndexPath
时,它启动我的Channel类并调用函数getChannelImageForChannelId:externalRefference:indexPath
。到目前为止一切都很好,现在我的通道类检查文件是否存在于本地,如果没有,它将下载它(使用ASIHttpRequest
)。此外,到目前为止一切顺利。现在当ASIHttpRequest在requestDidFinish上返回时,它会在一些结果后死掉。我注意到文件确实被下载了,因为经过几次尝试它就像一个魅力,因此我的代表似乎工作。
这是我的代码:
CellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CurrentChannelInfoCell";
CurrentChannelInfoCell *cell = (CurrentChannelInfoCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:nil options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[CurrentChannelInfoCell class]])
{
cell = (CurrentChannelInfoCell *)currentObject;
break;
}
}
}
NSArray *keys = [self.content allKeys];
id channelId = [keys objectAtIndex:indexPath.row];
NSDictionary *channel = [self.content objectForKey:channelId];
int cId = [(NSString*)channelId intValue];
[cell.textLabel setText:[channel objectForKey:@"name"]];
[cell.channelImage setHidden:YES];
Channel *theChannel = [[Channel alloc] init];
[theChannel setDelegate:self];
[theChannel getChannelImageForChannelId:cId externalRefference:[channel objectForKey:@"logotype"] indexPath:indexPath];
return cell;
}
- (void)didRecieveImageForChannel:(NSString*)imagePath indexPath:(NSIndexPath*)indexPath
{
NSLog(@"Did recieve the it.!");
}
我的代表,ChannelDelegate.h
:
#import <Foundation/Foundation.h>
@class Channel;
@protocol ChannelDelegate <NSObject>
@optional
- (void)didRecieveImageForChannel:(NSString*)imagePath indexPath:(NSIndexPath*)indexPath;
@end
Channel.h
:
#import <Foundation/Foundation.h>
#import "ChannelDelegate.h"
#import "Reachability.h"
#import "ASIHTTPRequest.h"
#import "ASINetworkQueue.h"
#import "ASIFormDataRequest.h"
@interface Channel : NSOperation <NSObject, ASIHTTPRequestDelegate>
{
ASINetworkQueue *networkQueue;
// Called on the delegate (if implemented) when the request completes successfully.
id <ChannelDelegate> delegate;
SEL didRecieveImageForChannelSelector;
}
@property (strong, nonatomic) id delegate;
@property (assign) SEL didRecieveImageForChannelSelector;
- (void)getChannelImageForChannelId:(int)channelId externalRefference:(NSString*)url indexPath:(NSIndexPath*)indexPath;
- (id)delegate;
@end
Channel.m
:
#import "Channel.h"
#import <objc/runtime.h>
@implementation Channel
static char kAssociationKey;
@synthesize didRecieveImageForChannelSelector;
@synthesize delegate;
- (void)getChannelImageForChannelId:(int)channelId externalRefference:(NSString*)url indexPath:(NSIndexPath*)indexPath
{
[self setDidRecieveImageForChannelSelector:@selector(didRecieveImageForChannel:indexPath:)];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *imagePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.gif", channelId]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:imagePath];
if (fileExists)
{
NSLog(@"Downloaded image!");
[[self delegate] performSelector:[self didRecieveImageForChannelSelector] withObject:imagePath withObject:indexPath];
}
else {
NSLog(@"Need to fetch it.!");
NSURL *theUrl = [NSURL URLWithString:url];
ASINetworkQueue *newQueue = [[ASINetworkQueue alloc] init];
[newQueue setRequestDidFinishSelector:@selector(channelImageFetched:)];
[newQueue setRequestDidFailSelector:@selector(processFailed:)];
[newQueue setDelegate:self];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theUrl];
[request setTimeOutSeconds:60];
[request setDownloadDestinationPath:imagePath];
[newQueue addOperation:request];
objc_setAssociatedObject(request, &kAssociationKey, indexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[newQueue go];
}
}
- (id)delegate
{
id d = delegate;
return d;
}
- (void)setDelegate:(id)newDelegate
{
delegate = newDelegate;
}
// Handle process two
- (void)channelImageFetched:(ASIHTTPRequest *)request
{
NSLog(@"channelImageFetched!");
NSIndexPath *indexPath = objc_getAssociatedObject(request, &kAssociationKey);
NSString *imagePath = request.downloadDestinationPath;
[[self delegate] performSelector:[self didRecieveImageForChannelSelector] withObject:imagePath withObject:indexPath];
NSLog(@"File downloaded!");
}
- (void) processFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
UIAlertView *errorView;
errorView = [[UIAlertView alloc]
initWithTitle: NSLocalizedString(@"Whoops!", @"Errors")
// message: NSLocalizedString(@"An error occured while preforming the request. Please try again.", @"Network error")
message: [error localizedDescription]
delegate: self
cancelButtonTitle: NSLocalizedString(@"Close", @"Errors") otherButtonTitles: nil];
[errorView show];
/* NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[request error], @"Error",
[request url], @"URL",
[[NSDate alloc] init], @"timestamp", nil];
[FlurryAPI logEvent:@"APNS-Could not fetch data." withParameters:dictionary timed:YES];
*/
}
@end
我收到的错误似乎不时有所不同,但这些似乎是我得到的错误:
2011-09-26 13:11:57.605 TVSports [4541:ef03]完成!
2011-09-26 13:11:57.609 TVSports [4541:ef03]已下载图片!
2011-09-26 13:11:57.610 TVSports [4541:ef03]收到了它!
2011-09-26 13:11:57.613 TVSports [4541:ef03]需要获取 if。!
2011-09-26 13:11:57.616 TVSports [4541:ef03]需要 取得它。!2011-09-26 13:11:57.618 TVSports [4541:ef03] 需要拿它。!2011-09-26 13:11:57.621 TVSports [4541:ef03]需要拿它。!2011-09-26 13:11:57.624 TVSports [4541:ef03]需要拿它。!
2011-09-26 13:11:57.629 TVSports [4541:ef03]需要获取 它。!2011-09-26 13:11:57.633 TVSports [4541:ef03]需要 取得它。!2011-09-26 13:11:57.663 TVSports [4541:ef03] 需要拿它。!2011-09-26 13:11:57.669 TVSports [4541:ef03]需要拿它。!2011-09-26 13:11:57.846 TVSports [4541:ef03] - [UIDeviceWhiteColor channelImageFetched:]:发送到实例的无法识别的选择器 0x65a1e30
2011-09-26 13:11:57.847 TVSports [4541:ef03] * 由于未捕获的异常而终止应用程序 'NSInvalidArgumentException',原因:' - [UIDeviceWhiteColor channelImageFetched:]:发送到实例的无法识别的选择器 0x65a1e30'
* 首先抛出调用堆栈:
(0x15da272 0x1769ce6 0x15dbf0d 0x1540e2f 0x1540c12 0x15dc092 0x3adf8 0x15dc092 0x24c43 0x15dc092 0xef9fac 0x15aec0f 0x15118c3 0x15111a4 0x1510b04 0x1510a1b 0x1ce6f67 0x1ce702c 0x608cf2 0x2718 0x2675 0x1)
终止称为投掷 异常(gdb)
或者我在ASIHTTPRequest的一行中获得了一个EXC_BAD_ACCESS(我无法重现最近10次尝试。)
任何人看起来我做错了吗?我的代码在哪里搞砸了?
答案 0 :(得分:0)
[UIDeviceWhiteColor channelImageFetched:]: unrecognized selector sent to instance 0x65a1e30
- 这告诉你的是“channelImageFetched”“message”被“发送”到UIDeviceWhiteController类型的对象。 (即,UIIDeviceWhiteController - &gt; channelImageFetched“被调用。)并且UIDeviceWhiteController没有名为”channelImageFetched“的方法。
虽然这可能是你的指针混淆的问题,但更有可能实现“channelImageFetched”的对象(你的对象)被过度释放和解除分配(你可以通过在你的NSLog中放置一个NSLog来确认这一点) dealloc例程。)所以你的问题很可能是常见的存储管理错误。
了解代理人的存储管理非常棘手。通常,当一个对象被交给一个委托对象时,它应该保留它并保持它,直到调用了所有可能的委托方法,此时第一个对象应该释放委托对象。但当然,在将其设置为委托之前,如果需要,在调用所有委托方法之后,您有责任保留委托对象。
[顺便说一句,虽然评论和诊断信息中的一点点幽默总是受到欢迎,但在你可能向其他人公开的任何代码中使用“motherf ...”是相当不专业的。]
答案 1 :(得分:0)
好吧,我还是不知道发生了什么......但似乎我找到了一个解决方法。
在mu Channel.m
文件中,我略微更改了内容。而不是使用NetworkQueue
我现在只是在请求对象上执行startAsynchronous
。
最终结果:
[...]
if (fileExists)
{
NSLog(@"Downloaded image!");
[[self delegate] performSelector:[self didRecieveImageForChannelSelector] withObject:imagePath withObject:indexPath];
}
else {
NSLog(@"Need to fetch the image!");
NSURL *theUrl = [NSURL URLWithString:url];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theUrl];
[request setDidFinishSelector:@selector(channelImageFetched:)];
[request setDidFailSelector:@selector(processFailed:)];
[request setTimeOutSeconds:60];
[request setDownloadDestinationPath:imagePath];
objc_setAssociatedObject(request, &kAssociationKey, indexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[request startAsynchronous];
}
[...]