簡體   English   中英

從SQLite加載查詢時,UIPickerView導致數組錯誤

[英]UIPickerView causing Array error when loading query from SQLite

新手程序員-這樣做是為了娛樂和學習。

我正在嘗試使用來自SQLite查詢的數據填充2個UIPickerView

每次運行此命令時,都會出現以下錯誤:

-[__NSArrayI length]: unrecognized selector sent to instance

我正在嘗試做的事情很簡單,這不應該是一個痛苦的問題。 您能否查看一下,並告訴我可能是什么原因引起的錯誤?

請注意,我去除了顯示元素的許多“蓬松”代碼-我知道這些代碼都不會引起任何問題。

燃油編輯器

#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

確保您的結果僅包含一個數組,且不得為數組列表。 我感覺像當你這樣做

return [results objectAtIndex:row];

它正在返回一個數組,而不是返回一個字符串。 可能是您的結果包含數組列表。 請驗證這件事。

錯誤是由於unrecognized selector 這意味着您要在任何方法中為數組調用長度函數或返回Array而不是字符串。

我已經檢查了您的代碼。請檢查以下部分:

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

    if (results !=nil) {

        return [results objectAtIndex:row];

    }

我認為[results objectAtIndex:row]返回一個數組而不是字符串。

請讓我知道結果...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM