0

我对 Xcode 和 Sqlite3 有点陌生,并且遵循了许多教程并在 SO 上花费了无数小时,但仍然坚持使用我正在尝试创建的简单 iPhone 应用程序添加到数据库。该应用程序有一个带有用于文本输入的文本字段的表单,我想将其保存到数据库中。我的故事板由两个输入字段和一个按钮(“AddEvalFormButton”)组成。

这就是发生的事情:

  1. 我确保模拟器已重置,然后我运行应用程序。只要我按下前一个屏幕中的按钮以获取评估表页面,它就会崩溃(我假设 ViewDidLoad 出了问题,但不确定)。但是,控制台显示以下内容:“您能够创建数据库”。(我也有一个 CreateOrOpenDB 断点(见下面的代码):0x1e4df: movl -12(%ebp), %edx <--这对我来说完全是胡说八道;任何关于如何使用此信息的想法将不胜感激)。

  2. 我关闭 iOS 模拟器并再次运行,这一次,它不会在打开表单屏幕时崩溃。我可以在文本字段中输入数据,但是当我点击 AddEvalFormButton 按钮时应用程序崩溃。这次控制台中没有消息。

问题:

  • 应用程序崩溃,我不知道为什么

  • 没有数据保存:我检查我的终端,发现没有表被添加到我的数据库中。

就我而言(如果我错了,请纠正我),我关心两个目录:

1) 我的 Xcode 项目的那个

2) 用户/库/应用程序支持/iPhone 模拟器

我有 4 个文件:EvaluationFormViewController.h、EvaluationFormViewController.m、EvalForm.h 和 EvalForm.m。它们如下所示:

评估表单视图控制器.h:

#import <UIKit/UIKit.h>
#import "sqlite3.h"
#import "EvalForm.h"

@interface EvaluationViewController : UIViewController <UIActionSheetDelegate, UITableViewDataSource, UITextFieldDelegate, UITextViewDelegate, UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UITextField *efq1Field;
@property (weak, nonatomic) IBOutlet UITextField *efq2Field;

- (IBAction)backgroundTouched:(id)sender;
- (IBAction)textfieldReturn:(id)sender;
- (IBAction)addEvalFormButton:(id)sender;

@end

评估表单视图控制器.m:

#import "EvaluationViewController.h"

@interface EvaluationViewController ()
{
    NSMutableArray *arrayOfEvalFormQs;
    sqlite3 *evalFormDB;
    NSString *dbPathString;
}
@property (nonatomic, readonly) CGPoint originalOffset;
@property (nonatomic, readonly) UIView *activeField;
@end

@implementation EvaluationViewController

@synthesize efq1Field, efq2Field;


//FROM TUTORIAL Cocoa W/Love; need the following instance variables
CGFloat animatedDistance;
//FROM TUTORIAL Cocoa W/Love; need the following instance constants
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;

- (IBAction)backgroundTouched:(id)sender {
    [efq1Field resignFirstResponder];
    [efq2Field resignFirstResponder];
}

//dismisses the keyboard when the return/done button is pressed for TextFields.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}
//dismisses the keyboard when the return/done button is pressed for TextViews.
- (BOOL)textViewShouldReturn:(UITextView *)textView
{
    [textView resignFirstResponder];
    return YES;
}


//FROM TUTORIAL: www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html

//Animate upwards when the text field is selected
//Get the rects of the text field being edited and the view that we're going to scroll. We convert everything to window coordinates, since they're not necessarily in the same coordinate space.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect textFieldRect =
    [self.view.window convertRect:textField.bounds fromView:textField];
    CGRect viewRect =
    [self.view.window convertRect:self.view.bounds fromView:self.view];

    //So now we have the bounds, we need to calculate the fraction between the top and bottom of the middle section for the text field's midline:
    CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
    CGFloat numerator =
    midline - viewRect.origin.y
    - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
    CGFloat denominator =
    (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
    * viewRect.size.height;
    CGFloat heightFraction = numerator / denominator;


    //Clamp this fraction so that the top section is all "0.0" and the bottom section is all "1.0".
    if (heightFraction < 0.0)
    {
        heightFraction = 0.0;
    }
    else if (heightFraction > 1.0)
    {
        heightFraction = 1.0;
    }


    //Now take this fraction and convert it into an amount to scroll by multiplying by the keyboard height for the current screen orientation. Notice the calls to floor so that we only scroll by whole pixel amounts.
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait ||
        orientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
    }
    else
    {
        animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
    }


    //Finally, apply the animation. Note the use of setAnimationBeginsFromCurrentState: — this will allow a smooth transition to new text field if the user taps on another.
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y -= animatedDistance;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

    [self.view setFrame:viewFrame];

    [UIView commitAnimations];
}


//ANIMATE BACK AGAIN:  The return animation is far simpler since we've saved the amount to animate.
- (void)textFieldDidEndEditing:(UITextField *)textField
{
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y += animatedDistance;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

    [self.view setFrame:viewFrame];

    [UIView commitAnimations];
}

//SAME CODE AS ABOVE, BUT FOR TEXTVIEW
//FROM TUTORIAL: www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html

//Animate upwards when the text field is selected
//Get the rects of the text field being edited and the view that we're going to scroll. We convert everything to window coordinates, since they're not necessarily in the same coordinate space.
- (void)textViewDidBeginEditing:(UITextView *)textView
{
    CGRect textFieldRect =
    [self.view.window convertRect:textView.bounds fromView:textView];
    CGRect viewRect =
    [self.view.window convertRect:self.view.bounds fromView:self.view];

    //So now we have the bounds, we need to calculate the fraction between the top and bottom of the middle section for the text field's midline:
    CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
    CGFloat numerator =
    midline - viewRect.origin.y
    - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
    CGFloat denominator =
    (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
    * viewRect.size.height;
    CGFloat heightFraction = numerator / denominator;


    //Clamp this fraction so that the top section is all "0.0" and the bottom section is all "1.0".
    if (heightFraction < 0.0)
    {
        heightFraction = 0.0;
    }
    else if (heightFraction > 1.0)
    {
        heightFraction = 1.0;
    }


    //Now take this fraction and convert it into an amount to scroll by multiplying by the keyboard height for the current screen orientation. Notice the calls to floor so that we only scroll by whole pixel amounts.
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait ||
        orientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
    }
    else
    {
        animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
    }

    //Finally, apply the animation. Note the use of setAnimationBeginsFromCurrentState: — this will allow a smooth transition to new text field if the user taps on another.
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y -= animatedDistance;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

    [self.view setFrame:viewFrame];

    [UIView commitAnimations];
}


//ANIMATE BACK AGAIN:  The return animation is far simpler since we've saved the amount to animate.
- (void)textViewDidEndEditing:(UITextView *)textView
{
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y += animatedDistance;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

    [self.view setFrame:viewFrame];

    [UIView commitAnimations];
}


/**Keyboard dismissed when background is clicked or when return is hit**/
- (IBAction)textfieldReturn:(id)sender{
    [sender resignFirstResponder];
}

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


- (void) viewWillDisappear: (BOOL)animated{

    [super viewWillDisappear:animated];

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc removeObserver:self name: UIKeyboardWillShowNotification object:nil];
    [nc removeObserver:self name: UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillAppear:(BOOL)animated
{
    [[self view] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"136676912132100.gif"]]];

}


//RELEVANT CODE FOR SQLITE ISSUE BELOW:
- (void)viewDidLoad
{
    [super viewDidLoad];

    //relating to sqlite:
    arrayOfEvalFormQs = [[NSMutableArray alloc]init];
    [self createOrOpenDB];

}

- (void)createOrOpenDB
{
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docPath = [path objectAtIndex:0];

    dbPathString = [docPath stringByAppendingPathComponent:@"evalForm.db"];   
    char *error;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:dbPathString]) {
        const char *dbPath = [dbPathString UTF8String];

        //creat db here
        if (sqlite3_open(dbPath, &evalFormDB)==SQLITE_OK) {
            const char *sql_stmt = "CREATE TABLE IF NOT EXISTS EVALFORMDB (ID INTEGER PRIMARY KEY AUTOINCREMENT, EFQ1 TEXT, EFQ2 TEXT)";
            NSLog(@"You were able to create DB");
            sqlite3_exec(evalFormDB, sql_stmt, NULL, NULL, &error);
            sqlite3_close(evalFormDB);
        }
        else {
            NSLog(@"Problem with createopenDB");
        }
    }
}

- (IBAction)addEvalFormButton:(id)sender {
    char *error;
    if (sqlite3_open([dbPathString UTF8String], &evalFormDB)==SQLITE_OK) {
        NSString *inserStmt = [NSString stringWithFormat:@"INSERT INTO EVALFORM(EFQ1,EFQ2) values ('%s', '%s')",[self.efq1Field.text UTF8String], [self.efq2Field.text UTF8String]];
        NSLog(@"I am in the loop");

        const char *insert_stmt = [inserStmt UTF8String];

        if (sqlite3_exec(evalFormDB, insert_stmt, NULL, NULL, &error)==SQLITE_OK) {   
            NSLog(@"Answer added");

            //not really sure what this does:
            EvalForm *evalForm = [[EvalForm alloc]init];
            [evalForm setEfq1:self.efq1Field.text];
            [evalForm setEfq2:self.efq2Field.text];
            [arrayOfEvalFormQs addObject:evalForm];
        }
        else{
            NSLog(@"Answer not added");
        }
        sqlite3_close(evalFormDB);
    }
}

@end

评估表格.h:

#import <Foundation/Foundation.h>

@interface EvalForm : NSObject

@property(nonatomic, strong)NSString *efq1;
@property(nonatomic, strong)NSString *efq2;

@end

评估表格.m:

#import "EvalForm.h"

@implementation EvalForm

@end

我已经尝试包含尽可能多的信息(可能有点矫枉过正,我很抱歉)。就像我提到的,我对 Xcode 和 SQLite 还是新手,所以我不确定我是否忽略了我的代码中的一些基本内容。任何关于我的代码为什么不起作用的输入将不胜感激。

4

0 回答 0