iOS: сбой приложения, вероятно, из-за создания экземпляра класса - PullRequest
0 голосов
/ 06 февраля 2012

Я пытаюсь отладить сбой, который я испытываю ...

Я получаю некоторые данные с веб-сервера, поэтому я настроил три класса: Child ChildConnection ChildParser

ChildConnection связывается с веб-службой, получает данные и запускает ChildParser, который затем анализирует xml и сохраняет его как дочерний объект ...

У меня это работает в проекте, где вместо этогоимея ChildConnection, я установил соединение в AppDelegate, и проблема, с которой я сталкиваюсь в своем текущем проекте, связана с делегатами (по крайней мере, так я думаю) ... так как я получаю ошибку: -[AppDelegate children]: нераспознанный селектор отправлен в экземпляр 0x6b07e80

Я вполне уверен, что ошибка вызвана: (ПРИМЕЧАНИЕ: я довольно новичок в этом)

- (ChildParser *) initChildParser {

    self = [super init];

    if(self)
    {
        childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
        NSLog(@"Init");
    }
    return self;
}

ChildConnection.h:

@interface ChildConnection : NSObject
{
    NSMutableArray *children;
    NSMutableData *webData;
}

@property (nonatomic, retain) NSMutableArray *children;

-(void)connectionSetUp;

@end

ChildConnection.m:

#import "ChildConnection.h"
#import "ChildParser.h"

@implementation ChildConnection
@synthesize children;

- (void)connectionSetUp
{
    NSString *soapMsg = 
    [NSString stringWithFormat:

    Soap message left out due to sensitive data
     ]; 


    NSURL *url = [NSURL URLWithString:@"Private"];
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];

    // Calculate the length of the post
    NSString *postLength =  [NSString stringWithFormat:@"%d", [soapMsg length]];

    // Set the headers
    [req addValue:postLength forHTTPHeaderField:@"Content-Length"];
    [req addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [req addValue:@"PRIVATE" forHTTPHeaderField:@"SOAPAction"];

    // Set the HTTP method and body
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody:[soapMsg dataUsingEncoding:NSUTF8StringEncoding]];

    NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self];

    if(myConnection)
    {
        NSLog(@"Connection established");
        webData = [NSMutableData data];
    } else
    {
        NSLog(@"Connection failed");
    }     
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{
    NSLog(@"didReceiveResponse");
    [webData setLength:0];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //NSLog(@"didReceiveData");
    [webData appendData:data];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", [error localizedDescription]);
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Finished loading");

    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:webData];

    //Initialize the delegate.
    ChildParser *parser = [[ChildParser alloc] initXMLParser];

    //Set delegate
    [xmlParser setDelegate:parser];

    //Start parsing the XML file.
    BOOL success = [xmlParser parse];
    /*
    if(success)
        NSLog(@"No Errors");
    else
        NSLog(@"Error Error Error!!!");
    */

    //NSLog(@"Count: %@", [ count]);
}

@end

ChildParser.h:

@class Child;
@class ChildConnection;

@interface ChildParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentElementValue;

    Child *aChild;

    ChildConnection *childConnection;
}

- (ChildParser *) initChildParser;

@end

.m:

#import "ChildParser.h"
#import "Child.h"
#import "ChildConnection.h"

@implementation ChildParser

- (ChildParser *) initChildParser {

    self = [super init];

    if(self)
    {
        childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
        NSLog(@"Init");
    }
    return self;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 
attributes:(NSDictionary *)attributeDict 
{
    NSLog(@"didstart");

    if([elementName isEqualToString:@"GetKidsResult"])
    {
        // initialize the array
        if(!childConnection.children)
        {
        childConnection.children = [[NSMutableArray alloc] init];

        }

    }

    else if([elementName isEqualToString:@"a:KeyValueOfintKidf4KEWLbb"])
    {
        if(!aChild)
        {
            //Initialize the child.
            aChild = [[Child alloc] init];
        }
    }

    //NSLog(@"Processing Element: %@", elementName);
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 

    NSLog(@"foundcharacters");
    /*
    if(!currentElementValue) 
    {
    currentElementValue = [[NSMutableString alloc] initWithString:string];
    }
    else
    {
    [currentElementValue appendString:string];
    }*/

}

 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
        //NSLog(@"El name: %@", elementName);

    if([elementName isEqualToString:@"GetKidsResult"])
    {
        NSLog(@"end of xml");
    return;    
    }

    if([elementName isEqualToString:@"a:KeyValueOfintKidf4KEWLbb"])
    {
        //NSLog(@"Found end of child");

        //[childConnection.children addObject:aChild];

        //NSLog(@"added");

        //int i = [childConnection.children count];
        //NSLog(@"Count: %d", i);
    //aChild = nil;
    }

    else if([elementName isEqualToString:@"a:Key"])
    {
        //NSLog(@"Found key: %@", currentElementValue);
        //aChild.key = [currentElementValue intValue];
        //NSLog(@"key: %@", aChild.key);
    }

    else if([elementName isEqualToString:@"b:CPR"])
    {
        //NSLog(@"Found cpr");
        //aChild.cpr = [currentElementValue intValue];
    }

    else if([elementName isEqualToString:@"b:CheckedIn"])
    {
        //NSLog(@"Found checkedIn");
        //aChild.checkedIn = [currentElementValue boolValue];
    }

    else if([elementName isEqualToString:@"b:FirstName"])
    {
        //NSLog(@"Found firstname: %@", currentElementValue);
        //[aChild setValue:currentElementValue forKey:@"firstName"];
        //aChild.firstName = currentElementValue;

    }

    else if([elementName isEqualToString:@"b:Gender"])
    {
        //NSLog(@"found gender");
        //aChild.gender = currentElementValue;
    }

    else if([elementName isEqualToString:@"b:Id"])
    {
        //NSLog(@"found id");
        aChild.idChild = [currentElementValue intValue];

    }

    else if([elementName isEqualToString:@"b:IsOnTour"])
    {
        //NSLog(@"found isontour");
        //aChild.isOnTour = [currentElementValue boolValue];

    }

    else if([elementName isEqualToString:@"b:LastName"])
    {
        //NSLog(@"found lastname: %@", currentElementValue);
        //aChild.lastName = currentElementValue;
    }

    else if([elementName isEqualToString:@"b:GroupName"])
    {
        //NSLog(@"found groupname");
        //aChild.groupName = currentElementValue;
    }

    currentElementValue = nil;


}

- (void)parserDidEndDocument:(NSXMLParser *)parser 
{
    NSLog(@"didEndDocument");

    //NSLog(@"Number of objects: %d", [childConnection.children count]);

    [[NSNotificationCenter defaultCenter] postNotificationName:@"finishedParsing" object:nil];
}

@end

ОБНОВЛЕНИЕ

Хорошо, так что немного дальше ... Теперь я получаю SIGABRTв классе, где я использую данные:

#import "AllView.h"
#import "CustomCellNoSubtitle.h"
#import "DTCustomColoredAccessory.h"
#import "Child.h"
#import "ChildConnection.h"

@implementation AllView

@synthesize allChildrenTable, childView, whichGroupLabel, charIndex;

-(void)receivedData
{
    NSLog(@"data update gotten");

    charIndex = [[NSMutableArray alloc] init];
    listOfNames = [[NSMutableArray alloc] init];

    for(int i=0; i<[childConnection.children count]-1; i++)
    {
        // get the person
        Child *aChild = [childConnection.children objectAtIndex:i];

        // get both first and last name and join them
        NSString *joinName = [NSString stringWithFormat:@"%@ %@", aChild.firstName, aChild.lastName];

        // save the full name to an array of all the names
        [listOfNames addObject:joinName];

        // get the first letter of the first name
        NSString *firstLetter = [aChild.firstName substringToIndex:1];

        NSLog(@"first letter: %@", firstLetter);

        // if the index doesn't contain the letter
        if(![charIndex containsObject:firstLetter])
        {
            // then add it to the index
            NSLog(@"adding: %@", firstLetter);
            [charIndex addObject:firstLetter];
        }

    }

    [allChildrenTable reloadData];
 }

}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Deselect the row, so it's clear when the user returns
    [allChildrenTable deselectRowAtIndexPath:indexPath animated:YES];

    if(self.childView == nil)
    {
        ChildView *cView = [[ChildView alloc] initWithNibName:@"ChildView" bundle:[NSBundle mainBundle]];

        self.childView  = cView;
    }

    [self.navigationController pushViewController:childView animated:YES];
}

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

    // set the number of sections in the table to match the number of first letters
    return [charIndex count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    // set the section title to the matching letter
    return [charIndex objectAtIndex:section];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    // get the letter in each section
    NSString *alphabet = [charIndex objectAtIndex:section];

    // get the names beginning with the letter
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet];

    NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];

    return [names count];
}

// set up an index
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return charIndex;
}

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

    static NSString *CellIdentifier = @"Cell";

    CustomCellNoSubtitle *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        //cell = [[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
        //cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        cell = [[CustomCellNoSubtitle alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        //cell.frame = CGRectZero;
    }
    /*
    //---get the letter in the current section---
    NSString *alphabet = [charIndex objectAtIndex:[indexPath section]];
    //---get all states beginning with the letter---
    NSPredicate *predicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@", alphabet];
    NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];
    if ([names count]>0) {
        //---extract the relevant state from the states object---
        NSString *cellValue = [names objectAtIndex:indexPath.row];
        cell.primaryLabel.text = cellValue;
    }

    cell.myImageView.image = [UIImage imageNamed:@"kidblank.png"];*/


    return cell;
}

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

    //childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
    childConnection =[[ChildConnection alloc] init];

    [allChildrenTable reloadData];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Set up a connection to the server to fetch the list of children
    ChildConnection *childConnection = [[ChildConnection alloc] init];
    [childConnection connectionSetUp];

    // Set up a listener to receive notice when the parser is done
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedData) name:@"finishedParsing" object:nil];

}

Ответы [ 2 ]

2 голосов
/ 06 февраля 2012

Ваше право, оскорбительный фрагмент кода:

if(self)
    {
        childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
        NSLog(@"Init");
    }

И причина, по которой вы приводите свой AppDelegate к объекту ChildConnection, вы не можете этого сделать, потому что это не ChildConnection.

Если вы хотите сослаться на ваш childConnection в AppDelegate, я рекомендую следующее:

+ (AppDelegate*)sharedDelegate;

//Implementation
+ (AppDelegate*)sharedDelegate {
    return (AppDelegate*)[[UIApplication sharedApplication] delegate];
}

Таким образом, вы ссылаетесь на свое childConnection следующим образом:

[AppDelegate sharedDelegate].childConnection;

Если вам нужны данные в тот момент, когда приложение запускает инициализацию childConnection в:

application:didFinishLaunchingWithOptions:
2 голосов
/ 06 февраля 2012

Проблема выглядит довольно просто.

В самой первой вставленной функции вы назначаете делегата приложения переменной childConnection.

childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];

Конечно, вы действительно хотите присвоить этому экземпляру новый экземпляр класса ChildConnection. Как это:

childConnection = [[ChildConnection alloc] init];

Я знаю, что ошибки Objective-C иногда бывает трудно понять, но то, что вы получаете, на самом деле довольно ясно:

[AppDelegate children]: unrecognised selector

Так что вы жалуетесь, что вы вызываете метод / свойство "children" в делегате приложения. Но зачем вам вызывать что-либо в делегате приложения, если вы его больше не используете? И зачем вам вызывать метод с именем «children», если он фактически определен как свойство класса ChildConnection, а не делегата приложения?

Ответ: поскольку объект, который вы считали ChildConnection, фактически является делегатом приложения.

ОБНОВЛЕНИЕ: похоже, вам нужно использовать ChildConnection более чем в одном месте. Самый простой способ сделать это - создать общий экземпляр. Добавьте этот метод в ваш класс ChildConnection:

+ (ChildConnection *)sharedConnection
{
    static ChildConnection *sharedConnection = nil;
    if (sharedConnection == nil)
    {
        sharedConnection = [[self alloc] init];
    }
    return sharedConnection;
}

Теперь в других ваших классах, где бы вы ни использовали [[ChildConnection alloc] init], используйте [ChildConnection sharedInstance] вместо.

...