从SQLite加载查询时UIPickerView导致Array错误

时间:2016-02-10 07:24:51

标签: ios objective-c sqlite

新手程序员 - 这样做是为了娱乐和学习..

我正在尝试用来自SQLite查询的数据填充2个UIPickerView

每次运行时,都会收到此错误:

-[__NSArrayI length]: unrecognized selector sent to instance

我想做的事情很简单,不应该是这个痛苦的问题。能否请您查看,并告诉我可能导致错误的原因?

请注意,我已经删除了很多用于显示元素的“蓬松”代码 - 我知道这些代码都没有导致任何问题..

FuelEdit.m

#import "FuelEdit.h"
#import "DBManager.h"

@interface FuelEdit ()

@property (nonatomic, strong) DBManager *dbManager;

@end

@implementation FuelEdit

@synthesize regoPicker;
@synthesize locationPicker;
@synthesize datePicker;

- (void)viewDidLoad
{

    self.dbManager = [[DBManager alloc] initWithDatabaseFilename:@"fuel.sql"];

    regoPicker.delegate = self;
    regoPicker.dataSource = self;
    locationPicker.delegate = self;
    locationPicker.dataSource = self;

    [regoPicker setShowsSelectionIndicator:YES];

}

- (void)viewWillAppear{

}

- (NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView
{
    if (pickerView == regoPicker) {

        return 1;

    } else if (pickerView == locationPicker) {

        return 1;

    } else {

        return 1;

    }
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {

    if (pickerView == regoPicker) {

    NSString *query = [NSString stringWithFormat:@"SELECT * FROM aircraft"];

    // Load the relevant data.
    NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

    return results.count;

    } else if (pickerView == locationPicker) {

        NSString *query = [NSString stringWithFormat:@"SELECT * FROM location"];

        // Load the relevant data.
        NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

        return results.count;

    } else {

        return 1;

    }
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {

    if (pickerView == regoPicker) {

        NSString *query = [NSString stringWithFormat:@"SELECT acrego FROM aircraft"];

        // Load the relevant data.
        NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

        if (results !=nil) {

            return [results objectAtIndex:row];

        } else {

            return nil;

        }

    } else if (pickerView == locationPicker) {

        NSString *query = [NSString stringWithFormat:@"SELECT locname FROM location"];

        // Load the relevant data.
        NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

        if (results != nil) {

            return [results objectAtIndex:row];

        } else {

            return nil;

        }

    } else {

        return 0;

    }
}

FuelEdit.h

#import <UIKit/UIKit.h>

@protocol FuelEditDelegate

@end

@interface FuelEdit : UITableViewController <UITableViewDelegate, UITableViewDataSource, UIPickerViewDataSource, UIPickerViewDelegate>

@property (nonatomic, strong) id<FuelEditDelegate> delegate;

@property (weak, nonatomic) IBOutlet UIPickerView *regoPicker;

@property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;

@property (weak, nonatomic) IBOutlet UIPickerView *locationPicker;

@end

DBManager.m:

#import <Foundation/Foundation.h>
#import "DBManager.h"
#import <sqlite3.h>

@interface DBManager()

@property (nonatomic, strong) NSString *documentsDirectory;

@property (nonatomic, strong) NSString *databaseFilename;

@property (nonatomic, strong) NSMutableArray *arrResults;

-(void)copyDatabaseIntoDocumentsDirectory;

-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable;

@end

@implementation DBManager

-(instancetype)initWithDatabaseFilename:(NSString *)system{
    self = [super init];
    if (self) {
        // Set the documents directory path to the documentsDirectory property.
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        self.documentsDirectory = [paths objectAtIndex:0];

        // Keep the database filename.
        self.databaseFilename = system;

        // Copy the database file into the documents directory if necessary.
        [self copyDatabaseIntoDocumentsDirectory];
    }
    return self;
}

-(void)copyDatabaseIntoDocumentsDirectory{
    // Check if the database file exists in the documents directory.
    NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
    if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
        // The database file does not exist in the documents directory, so copy it from the main bundle now.
        NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
        NSError *error;
        [[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];

        // Check if any error occurred during copying and display it.
        if (error != nil) {
            NSLog(@"Copy Database Error: %@", [error localizedDescription]);
        }
    }
}

-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable{
    // Create a sqlite object.
    sqlite3 *sqlite3Database;

    // Set the database file path.
    NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];

    // Initialize the results array.
    if (self.arrResults != nil) {
        [self.arrResults removeAllObjects];
        self.arrResults = nil;
    }
    self.arrResults = [[NSMutableArray alloc] init];

    // Initialize the column names array.
    if (self.arrColumnNames != nil) {
        [self.arrColumnNames removeAllObjects];
        self.arrColumnNames = nil;
    }
    self.arrColumnNames = [[NSMutableArray alloc] init];


    // Open the database.
    BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
    if(openDatabaseResult == SQLITE_OK) {
        // Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
        sqlite3_stmt *compiledStatement;

        // Load all data from database to memory.
        BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
        if(prepareStatementResult == SQLITE_OK) {
            // Check if the query is non-executable.
            if (!queryExecutable){
                // In this case data must be loaded from the database.

                // Declare an array to keep the data for each fetched row.
                NSMutableArray *arrDataRow;

                // Loop through the results and add them to the results array row by row.
                while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
                    // Initialize the mutable array that will contain the data of a fetched row.
                    arrDataRow = [[NSMutableArray alloc] init];

                    // Get the total number of columns.
                    int totalColumns = sqlite3_column_count(compiledStatement);

                    // Go through all columns and fetch each column data.
                    for (int i=0; i<totalColumns; i++){
                        // Convert the column data to text (characters).
                        char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);

                        // If there are contents in the currenct column (field) then add them to the current row array.
                        if (dbDataAsChars != NULL) {
                            // Convert the characters to string.
                            [arrDataRow addObject:[NSString  stringWithUTF8String:dbDataAsChars]];
                        }

                        // Keep the current column name.
                        if (self.arrColumnNames.count != totalColumns) {
                            dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
                            [self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
                        }
                    }

                    // Store each fetched data row in the results array, but first check if there is actually data.
                    if (arrDataRow.count > 0) {
                        [self.arrResults addObject:arrDataRow];
                    }
                }
            }
            else {
                // This is the case of an executable query (insert, update, ...).

                // Execute the query.
                //BOOL executeQueryResults = sqlite3_step(compiledStatement);
                //if (executeQueryResults == SQLITE_DONE) {
                if (sqlite3_step(compiledStatement)) {
                // Keep the affected rows.
                    self.affectedRows = sqlite3_changes(sqlite3Database);

                    // Keep the last inserted row ID.
                    self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
                }
                else {
                    // If could not execute the query show the error message on the debugger.
                    NSLog(@"DB Error: %s", sqlite3_errmsg(sqlite3Database));
                }
            }
        }
        else {
            // In the database cannot be opened then show the error message on the debugger.
            NSLog(@"%s", sqlite3_errmsg(sqlite3Database));
        }

        // Release the compiled statement from memory.
        sqlite3_finalize(compiledStatement);

    }

    // Close the database.
    sqlite3_close(sqlite3Database);
}

-(NSArray *)loadDataFromDB:(NSString *)query{
    // Run the query and indicate that is not executable.
    // The query string is converted to a char* object.
    [self runQuery:[query UTF8String] isQueryExecutable:NO];

    // Returned the loaded results.
    return (NSArray *)self.arrResults;
}

-(void)executeQuery:(NSString *)query{
    // Run the query and indicate that is executable.
    [self runQuery:[query UTF8String] isQueryExecutable:YES];
}


@end

2 个答案:

答案 0 :(得分:1)

确保您的结果只包含一个数组,但它不能是数组列表。当你这样做时,我感觉很像

return [results objectAtIndex:row];

它返回一个数组而不是返回一个字符串。可能是您的结果包含数组列表。请验证这件事。

答案 1 :(得分:-1)

错误是unrecognized selector。这意味着您正在为数组调用length函数或在任何方法中返回Array而不是string。

我已检查过你的代码。请查看以下部分:

    NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];

    if (results !=nil) {

        return [results objectAtIndex:row];

    }

我认为[results objectAtIndex:row]正在返回一个数组而不是字符串。

请告诉我结果......