新手程序员 - 这样做是为了娱乐和学习..
我正在尝试用来自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
答案 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]
正在返回一个数组而不是字符串。
请告诉我结果......