ios - 在 arc : EXC_BAD_ACCESS 中消失的 self.delegate

标签 ios objective-c delegates refresh exc-bad-access

我有一个 SurroundViewController (CollectionView),它显示从网络服务器加载的图像。如果您单击图像,您将被导航到 DetailViewController (TableView),它显示图像的附加信息。两者都嵌入在 NavigationController 中(参见 Storyboard图像)。

Storyboard of ViewController setup

当我在 SurroundViewController 中进行刷新时,当我从 DetailViewController 返回时,我的问题就开始了。然后它在 performSelector 行上崩溃并显示 EXC_BAD_ACCESS

WebApi.m

-(void)getSurroundStream {

    NSString *URLString = [NSString stringWithFormat:@"%@/%@/view/%f/%f", kApiHost, kApiPath, self.sshare.coordinate.longitude, self.sshare.coordinate.latitude];
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    [self setAuthHeader:manager];

    [manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [self.sshare putViData:responseObject];

        [self.delegate performSelector:@selector(didLoadFoo)]; // --> EXC_BAD_ACCESS

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [self.error vError:error message:operation.responseString url:URLString];
    }];
}

我检查了调试控制台:

2014-03-11 14:22:51.989 Foo[6923:60b] -[SurroundViewController refresh:] [Line 352] refreshing
2014-03-11 14:22:51.998 Foo[6923:60b] -[WebApi getSurroundImages] [Line 393] do surround composition
(lldb) po self.delegate
[no Objective-C description available]

好像是哪个对象不可用。我不明白的是。我在 SurroundViewController 中并通过 pull-to-refresh 主动刷新。所以我在环绕 View 中,对象应该可用...

如何解决这个问题,应用程序不会因 performSelector 行的 EXC_BAD_ACCESS 而崩溃?

这是与问题相关的代码(必要部分):

SurroundViewController.h

#import <UIKit/UIKit.h>
#import "WebApi.h"
#import "DetailViewController.h"
#import "SingletonClass.h"

@interface SurroundViewController : UICollectionViewController <WebApiDelegate>

@property (nonatomic, strong) WebApi *swebapi;
@property (nonatomic, strong) SingletonClass *sshare;

@end

SurroundViewController.m

#import "SurroundViewController.h"

@interface SurroundViewController ()

@property (nonatomic, strong) UIRefreshControl *refresh;

@end

@implementation SurroundViewController

-(void)vinit {
    self.sshare = [SingletonClass sharedInstance];
    self.swebapi = [WebApi sharedInstance];
    self.swebapi.delegate = self;
}

- (void)viewDidLoad
{
    [self vinit];
    [self.navigationController setNavigationBarHidden:YES animated:NO];
    [super viewDidLoad];

    [self addRefresh];
    [self.swebapi getSurroundImages]; // will call delegate didComposition

}

- (void)viewDidAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:NO];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    // cell configuration 
}


-(void)addRefresh {
    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    [refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];

    self.refresh = refreshControl;
    [self.collectionView addSubview:self.refresh];
}

-(void)refresh:(UIRefreshControl*)refresh {

    refresh.attributedTitle = [[NSAttributedString alloc] initWithString:@"Refreshing..."];
    [self.swebapi getSurroundImages];

}

-(void)didLoadFoo {
    [self.swebapi doComposition];
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    [self performSegueWithIdentifier:@"toDetailView" sender:indexPath];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"toDetailView"]) {
        DetailViewController *dvc = [segue destinationViewController];

        NSIndexPath *indexPath = sender;

       dvc.idx = [self getItemOfSection:indexPath];
       dvc.detailData = [[self.sshare coItem:dvc.idx] mutableCopy];      
    }
}

- (int)getItemOfSection:(NSIndexPath *)indexPath {
    return (int)indexPath.item + ((int)indexPath.section * 4);
}

@end

网络接口(interface).h

#import "AFHTTPRequestOperationManager.h"
#import "Errors.h"

@class WebApi;
@protocol WebApiDelegate <NSObject>

@optional
-(void)didLoadFoo;

@end

@interface WebApi : AFHTTPRequestOperationManager <SingletonDelegate>

@property (assign, nonatomic)id<WebApiDelegate> delegate;
@property (nonatomic, strong) Errors *error;

+(WebApi*)sharedInstance;

-(void)getSurroundStream;
-(void)getSurroundImages;

@end

WebApi.m

#import "WebApi.h"

#define kApiHost @"http://sample.com"
#define kApiPath @"sample"

@implementation WebApi

-(WebApi*)initWithBaseURL:url {
    self = [super init];
    if (self != nil) {
        self.sshare = [SingletonClass sharedInstance];
        self.error = [[Errors alloc] init];
    }
    return  self;
}

+(WebApi*)sharedInstance
{
    static WebApi *sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kApiHost]];
    });

    return sharedInstance;
}
-(void)getSurroundStream {

    NSString *URLString = [NSString stringWithFormat:@"%@/%@/view/%f/%f", kApiHost, kApiPath, self.sshare.coordinate.longitude, self.sshare.coordinate.latitude];
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    [self setAuthHeader:manager];

    [manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [self.sshare putViData:responseObject];

        [self.delegate performSelector:@selector(didLoadFoo)]; // --> EXC_BAD_ACCESS

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [self.error vError:error message:operation.responseString url:URLString];
    }];
}


-(void)getSurroundImages {
    [self getSurroundStream]; 
}
@end

单例类.h

#import <Foundation/Foundation.h>

@class Singleton;
@protocol SingletonDelegate <NSObject>

-(void)didRefreshToken;

@end

@interface SingletonClass : NSObject

@property (assign, nonatomic) id<SingletonDelegate> delegate;

@property (nonatomic, strong) NSMutableArray *viData;
@property (nonatomic, strong) NSMutableArray *coData; 

@end

单例类.m

#import "SingletonClass.h"

@implementation SingletonClass

static SingletonClass *sharedInstance = nil;

// Get the shared instance and create it if necessary.
+ (SingletonClass *)sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
}

- (id)init
{
    self = [super init];    
    if (self) {
        self.coData = [[NSMutableArray alloc] init]; 
        self.viData = [[NSMutableArray alloc] init]; 
    }    
    return self;
}

// We don't want to allocate a new instance, so return the current one.
+ (id)allocWithZone:(NSZone*)zone {
    return [self sharedInstance];
}

// Equally, we don't want to generate multiple copies of the singleton.
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
-(NSMutableDictionary *)coItem:(int)position {
    NSAssert(self.coData.count > position, @"Position does not exists: coData.count: %lu > position: %d", (unsigned long)self.coData.count, position);

    return self.coData[position];
}

@end

DetailViewController.h

#import <UIKit/UIKit.h>
#import "SingletonClass.h"
#import  "WebApi.h"

@interface DetailViewController : UITableViewController <WebApiDelegate>

@property (nonatomic) int idx;
@property (nonatomic, strong) SingletonClass *sshare;
@property (nonatomic, strong) WebApi *swebapi;
@property (nonatomic, strong) NSMutableDictionary *detailData;

@end

DetailViewController.m

#import "DetailViewController.h"

@interface DetailViewController ()

@property (nonatomic, strong) NSArray *cellRows;

@end

@implementation DetailViewController

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}
- (void)vinit {

    self.sshare = [SingletonClass sharedInstance];

    self.swebapi = [WebApi sharedInstance];
    self.swebapi.delegate = self;

    NSAssert(self.detailData, @"detailData is not available");
}

- (void)viewDidLoad
{
    [self vinit];
    [self.navigationController setNavigationBarHidden:NO animated:NO];
    [super viewDidLoad];

    self.cellRows = @[@"cellLocation:", @"cellIntention:"];
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.cellRows.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"detailCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    // Configure the cell...

    SEL functionCall = NSSelectorFromString(self.cellRows[indexPath.row]);
    [self performSelector:functionCall withObject:cell];

    return cell;
}


- (void)cellLocation:(UITableViewCell*)cell {
    // configuration of table cell    
}

- (void)cellIntention:(UITableViewCell*)cell {
    // configuration of table cell    
}

@end

最佳答案

您正在将 DetailViewController 设置为委托(delegate)。当然,你会在它被释放后得到 EXC_BAD_ACCESS 。 您应该使用通知代替共享实例的委托(delegate)。 - (void)addObserver:(id)notificationObserver 选择器:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender- (void)removeObserver:(id)notificationObserver 是你的 friend 。

关于ios - 在 arc : EXC_BAD_ACCESS 中消失的 self.delegate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22328190/

相关文章:

iphone - iphone模拟器是否能够显示航向和纬度,经度?

ios - 在解析iOS中搜索1000多个查询

c# - "a field initializer cannot reference non static fields"在 C# 中是什么意思?

c# - 无法将类型 `UnityEngine.Events.UnityAction<string>' 隐式转换为 `UnityEngine.Events.UnityAction'

objective-c - 在登录项启动具有 root 授权的应用程序?

c# - 一种在开放委托(delegate)和封闭委托(delegate)之间执行转换的方法

ios - 为什么有时不调用完成处理程序?

iphone - 在前向类对象上找不到属性?

ios - 一个View上有两个UITableView

iphone - 在 Web 服务之前加载 UITableViewController