1

ログイン後に顧客の顧客固有のレポートのリストをコンパイルするアプリがあります。これらのレポートが表示され、PDF ファイルをダウンロードしてアプリ内で表示できるようにする「表示」ボタンを配置しました。

この段階では、表示ボタンを押すとメモリに問題があるように見えますが、問題の場所を見つける方法がわかりません。ここに私のコードがあります:

#import "reportsTestViewController.h"
#import "ReportsDataObject.h"
#import "Session.h"
#import "AFNetworking.h"
@interface reportsTestViewController ()

@end

@implementation reportsTestViewController

@synthesize response;

@synthesize myDataIvar;

@synthesize viewReportPressed;


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    reportsTable.delegate = self;
    reportsTable.dataSource = self;
    self.sections = [[NSMutableDictionary alloc] init];

    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

#pragma mark NSURLConnection Delegate Methods
//    

    //Create your request pointing to the test page
   NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.tesg.com.au/allCustBuild.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];


    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    //initialize it when you create your connection
    if (connection){
        self.myDataIvar = [[NSMutableData alloc] init];
    }
}

    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        [self.myDataIvar setLength:0];
    }

    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        [self.myDataIvar appendData:data];

    }

    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        NSLog(@"Connection Failed: %@", error.userInfo);
    }

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    //this is where you would parse the data received back from the server
    NSString *responseString = [[NSString alloc] initWithData:self.myDataIvar encoding:NSUTF8StringEncoding];
    NSLog(@"Received Data: %@",responseString);
    [self setupReportsFromJSONArray:self.myDataIvar];

}

-(void)connectionWasASuccess:(NSData *)data{
    [self setupReportsFromJSONArray:data];

}



-(void)setupReportsFromJSONArray:(NSData*)dataFromReportsArray{
    BOOL found;
    NSError *error;
   // NSMutableArray *reportsArray = [[NSMutableArray alloc] init];
    NSArray *arrayFromServer = [NSJSONSerialization JSONObjectWithData:dataFromReportsArray options:0 error:&error];

    if(error){
        NSLog(@"error parsing the json data from server with error description - %@", [error localizedDescription]);
    }

    else {
        reportsArray = [[NSMutableArray alloc] init];
        for(NSDictionary *eachReport in arrayFromServer)
        {

            ReportsDataObject *report = [[ReportsDataObject alloc] initWithJSONData:eachReport];

            [reportsArray addObject:report];
            NSString *c = [[eachReport objectForKey:@"title"] substringToIndex:3];
                      found = NO;

            for (NSString *str in [self.sections allKeys])
            {
                if ([str isEqualToString:c])
                {
                    found = YES;
                }
            }

            if (!found)
            {
                [self.sections setValue:[[NSMutableArray alloc] init] forKey:c];
            }
        }

        }
        NSLog(@"Array Populated");
        NSLog(@"%u reports found",reportsArray.count);
        //Now you have your reportsArray filled up with all your data objects



for (NSDictionary *eachReport in arrayFromServer)
{
   [[self.sections objectForKey:[[eachReport objectForKey:@"title"] substringToIndex:3]] addObject:eachReport];
}

// Sort each section array
for (NSString *key in [self.sections allKeys])
{
    [[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES]]];


}

[reportsTable reloadData];
}


-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)viewReportPressed:(UIButton*)button {

    NSLog(@"Button successfully Pressed");
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    NSURL *URL = [NSURL URLWithString:@"http://tesg.com.au/portal/media/reports/1367365180_367 Collins Passive April 2013.pdf"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *theResponse) {
        NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
        return [documentsDirectoryPath URLByAppendingPathComponent:[theResponse suggestedFilename]];
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
        NSLog(@"File downloaded to: %@", filePath);
    }];
    [downloadTask resume];

                                              }


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    NSUInteger count = [[self.sections allKeys] count];
    NSLog(@"Number of sections: %d", count);
    return count;
}




- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section];
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    //We check against table to make sure we are displaying the right number of cells
    // for the appropriate table. This is so that things will work even if one day you
    //decide that you want to have two tables instead of one.

    {
        NSUInteger count = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section]] count];
        NSLog(@"Number of rows in section: %d", count);
        return count;
    }
}
//- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
        //return [[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
   // }





-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{


    static NSString *cellIdentifier = @"Cell";



    UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell)
    {


        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];

    }

        //The beauty of this is that you have all your data in one object and grab WHATEVER you like
    //This way in the future you can add another field without doing much.
    NSUInteger count = [[self.sections allKeys] count];
    if(count == 0){
        cell.textLabel.text = @"no reports to show";
    }
    else{
        NSDictionary *Reports = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];

        cell.textLabel.text = [Reports objectForKey:@"title"];
        cell.detailTextLabel.text = [Reports objectForKey:@"building"];








        UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [button addTarget:self action:@selector(viewReportPressed:) forControlEvents:UIControlEventTouchUpInside];
        [button setTitle:@"View" forState:UIControlStateNormal];

        button.frame = CGRectMake(180.0f, 5.0f, 150.0f, 30.0f);
        [cell addSubview:button];


        // in the future you can grab whatever data you need like this
        //[currentReport buildingName], or [currentReport reportName];
    }


    return(cell);

        }




@end

いずれかのセルで表示ボタンを押すと、「ボタンが正常に押されました」という NSLog が表示されますが、エラーが発生してすぐにクラッシュします。

[downloadTask resume];             Thread 1:EXC_BAD_ACCESS (code=2, address=0x0)

これを修正する方法はありますか?

4

1 に答える 1

4

EXC_BAD_ACCESSのアドレスでが得られた場合0x0、それは通常、許可されていないnilコンテキストで値が使用されたことを意味します。nil

この場合、URL 文字列が有効でないことが原因です。スペースは使用できません。したがって、結果のURL変数はnilであり、説明した動作になります。おそらく、URL 文字列をパーセント エスケープする必要があります。たとえば、次のようになります。

NSString *URLString = @"http://tesg.com.au/portal/media/reports/1367365180_367 Collins Passive April 2013.pdf";
NSURL *URL = [NSURL URLWithString:[URLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

将来この種の例外を識別するために、例外ブレークポイントを使用できます。これは、多くの場合、問題のあるコード行を識別するのに役立ちます。nilまたは、値を受け入れないメソッドに意図せずに値を渡してしまった可能性がないか、コード コードを注意深く確認してください。


ただし、EXC_BAD_ACCESS以外の値の を取得した場合0x0は、多くの場合、以前に割り当てを解除したオブジェクトを使用しようとした結果です。(常にではありませんが、頻繁に発生します。幸いなことに、ARC はこの種の問題をあまり一般的ではありません。) 明らかに、ここではそうではありませんが、以前に割り当て解除されたオブジェクトを使用しようとする状況をどのように特定するかを尋ねました。

その状況を診断するには、通常、「ゾンビ」をオンにします (「診断を使用してアプリケーションを実行する」を参照)。ところで、ゾンビの診断が終了したら、ゾンビをオンのままにしたくないので (特に本番アプリでは) ゾンビをオフに戻してください。

とにかく、この場合、アドレスは だったので、0x0オブジェクトの割り当てが解除された結果ではなく、nil無効な URL によって引き起こされた値の不適切な使用が問題でした。

于 2014-03-20T06:02:04.900 に答える