Search code examples
objective-cipaduitableviewios6

UITableView in a UIViewController on an iPad


I'm trying to develop a tiny app to manage the registry for a teacher. My app works so:

  1. I present a UIViewController (only landscape) to select the class.
  2. When I press the button (for example: 1F), I call a method to parse an XML file in which I got the name and the surname of the students. So I put this name and surname into an NSArray of NSDictionary (arrayStudents[0] = dictStudents and dictStudents is composed by 3 key: number, name and surname).
  3. In the second UIViewController I put a UITableView on the left of the screen and a normal view to the right. In the UITableView I want to have the name and surname of the students and on the right I want to show the score about test of the student selected by tapping on the UITableView.

This is how my viewController looks like:

viewController UI

My problem is how to populate the UITableView. I connected the tableView with an IBOutlet to my second viewController and then I connect the delegate and the dataSource to the second viewController, but the app is still crashing. I will post here the code of my table view class and second view controller, so you can help me to fix this problem.

Here you can see the connection tab of my tableView:

connection tab

tableView.h

#import <UIKit/UIKit.h>

@interface tableView : UITableView <UITableViewDelegate,UITableViewDataSource>
@property (nonatomic, strong) NSMutableArray *arrayStudents;
@end

tableView.m

#import "tableView.h"

@implementation tableView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

#pragma mark - Table view data source

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

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    cell.textLabel.text = [self.arrayStudents[indexPath.row] objectForKey:@"name"];
    cell.detailTextLabel.text = [self.arrayStudents[indexPath.row] objectForKey:@"surname"];

    return cell;
}

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

}

@end

detailsViewController.h

    #import <UIKit/UIKit.h>

    @interface DetailsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
    @property (weak, nonatomic) IBOutlet UITableView *tableViewStudentsNameAndSurname;
    @property (weak, nonatomic) IBOutlet UIView *viewDetails;
    @property (weak, nonatomic) IBOutlet UILabel *labelName;
    @property (weak, nonatomic) IBOutlet UILabel *labelSurname;
    @property (weak, nonatomic) IBOutlet UITextField *textFieldTest1;
    @property (weak, nonatomic) IBOutlet UITextField *textFieldTest2;
    @property (weak, nonatomic) IBOutlet UITextField *textFieldTest3;
    @property (weak, nonatomic) IBOutlet UITextField *textFieldText4;
    @property (weak, nonatomic) IBOutlet UITextView *textViewValutation;
    @property (weak, nonatomic) IBOutlet UILabel *labelTotalScore;
    @property (nonatomic, strong) NSString *fileName;

    - (IBAction)saveDataToPlistFile:(id)sender;
    @end

detailsViewController.m

#import "DetailsViewController.h"
#import "ParserXML.h"
#import "tableView.h"

@interface DetailsViewController () {
    ParserXML *parser;
    tableView *table;
}
@end

@implementation DetailsViewController

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

    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    parser = [[ParserXML alloc] init];
    NSLog(@"DetailsViewController: %@", self.fileName);
    parser.fileName = self.fileName;
    [parser parseXML];
    table = [[tableView alloc] init];
    table.arrayStudents = [parser.arrayStudents mutableCopy];
}

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

- (IBAction)saveDataToPlistFile:(id)sender {

}
@end

ParserXML.h

#import <Foundation/Foundation.h>

@interface ParserXML : NSObject <NSXMLParserDelegate>
@property (nonatomic, strong) NSMutableArray *arrayStudents;
@property (nonatomic, strong) NSDictionary *dictStudents;
@property (nonatomic, strong) NSString *fileName;

- (void) parseXML;
@end

ParserXML.m

#import "ParserXML.h"

@interface ParserXML() {
    NSXMLParser *nameStudentParser;
    NSString *pathXmlFile;
}
@end

@implementation ParserXML

- (id) init {
    self = [super init];
    if (self) {
        self.arrayStudents = [[NSMutableArray alloc] init];
        pathXmlFile = [[NSBundle mainBundle] pathForResource:self.fileName ofType:@"xml"];
    }
    return self;
}

- (void) parseXML {
    NSURL *xmlUrl = [NSURL URLWithString:pathXmlFile];
    NSString *host = [xmlUrl host];
    if (xmlUrl == nil || host == nil) {
        NSData *data = [[NSData alloc] initWithContentsOfFile:pathXmlFile];
        nameStudentParser = [[NSXMLParser alloc] initWithData:data];
    } else {
        nameStudentParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlUrl];
    }
    [nameStudentParser setDelegate:self];
    [nameStudentParser setShouldProcessNamespaces:NO];
    [nameStudentParser setShouldReportNamespacePrefixes:NO];
    [nameStudentParser setShouldResolveExternalEntities:NO];
    [nameStudentParser parse];
}

- (void)parserDidStartDocument:(NSXMLParser *)parser {
    NSLog(@"File trovato inizio il parsing del documento");
}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    NSLog(@"Errore Parsing");
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    if ([elementName isEqualToString:@"students"]) {
    } else if ([elementName isEqualToString:@"student"]) {
        NSString *numberValue = attributeDict[@"number"];
        NSString *nameValue = attributeDict[@"name"];
        NSString *surnameValue = attributeDict[@"surname"];

        //Inserire dizionario di array
        self.dictStudents = @{@"number": numberValue,
                                @"name": nameValue,
                            @"surname" : surnameValue};

        [self.arrayStudents addObject:self.dictStudents];
        NSLog(@"arrayStudents dim = %d", self.arrayStudents.count);
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

}

- (void)parserDidEndDocument:(NSXMLParser *)parser {
    NSLog(@"ArrayFuels = %@", self.arrayStudents);
}

@end

When I run the app Xcode says:

[DetailsViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x751da40

Can you help me to fix that problem? What I'm doing wrong?


Solution

  • Okay, So I'm pretty new to objective C so this is not an expert opinion. But from what I get, it is looking for the delegate method that should be there in DetailsViewController class. You have connected your table view delegate/datasource to DetailsViewController class, I think you're supposed to specify the class as being the delegate class of UITableView as well. In DetailsViewController.h:

    @interface DetailsViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
    

    and then plug in the UITableView Delegate methods in DetailsViewController.m file. Although, what I don't get is why are you using 2 table view classes? If you want to use tableView class, why not initialize in DetailsViewController::viewDidLoad and simply:

    [self.view addSubView:tableView]  
    

    I don't think there is a need for tableViewStudentsNameAndSurname in your class.