Проблемы с пользовательскими делегатами - PullRequest
0 голосов
/ 26 сентября 2011

Это один из моих первых попыток написать своих собственных делегатов.Я использую iOS5 Beta 7 и пишу свою делегатскую функцию.

Что нужно сделать, так это чтобы таблица (MyTableController) загружала список телеканалов.Это словарь, содержащий ключ «логотип», который является 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] Нужно достать, если!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:]: нераспознанный селектор отправлен на экземпляр 0x65a1e302011-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)

Или я получаю EXC_BAD_ACCESS для строки в ASIHTTPRequest (которую я не могу воспроизвести за последние 10 попыток.) ​​

Может кто-нибудь показывать, чтоЯ делаю не так?Где весь мой код испорчен?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2011

Ну, я до сих пор не знаю, что случилось .. но похоже, что я нашел работу вокруг.

В файле 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];
    }
[...]
0 голосов
/ 26 сентября 2011

[UIDeviceWhiteColor channelImageFetched:]: unrecognized selector sent to instance 0x65a1e30 - Это говорит о том, что сообщение «channelImageFetched» «было« отправлено »объекту типа UIDeviceWhiteController.(То есть UIIDeviceWhiteController -> channelImageFetched "был вызван.) И у UIDeviceWhiteController нет метода с именем" channelImageFetched ".

Хотя это может быть проблемой, когда вы путаете ваши указатели, скорее всего объект (вашобъект), который реализует «channelImageFetched», был перевыпущен и освобожден (вы можете подтвердить это, поместив NSLog в вашу процедуру dealloc.) Таким образом, ваша проблема, скорее всего, является общей ошибкой управления хранилищем.

Понимание управления хранилищемс делегатами довольно сложно. Обычно, когда объекту передается объект делегата, он должен сохранять его и сохранять его до тех пор, пока не будут вызваны все возможные методы делегата, после чего первый объект должен освободить объект делегата. Но, конечно, егоВы обязаны сохранить объект делегата до его установки в качестве делегата и, если необходимо, после того, как были вызваны все методы делегата.

[КСТАТИ, пока немного хорошего настроения в комментариях и диагностикевсегда приветствуются stic сообщения, довольно непрофессионально использовать «motherf ...» в любом коде, который вы можете передать другим.]

...