蔬菜报价表

蔬菜报价表

#import "ViewController.h"

#import "Manager.h"

@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>

@property (weak, nonatomic) IBOutlet UITableView *vegListView;

@property(weak,nonatomic)UIAlertController* vegController;

@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    

    //添加委托代理对象并声明协议

    _vegListView.delegate=self;

    _vegListView.dataSource=self;

    

    //增加一个导航栏上的按键

    UIBarButtonItem* rightBarBtn=[[UIBarButtonItem alloc]initWithTitle:@"增加" style:UIBarButtonItemStylePlain target:self action:@selector(addVegetables)];

    [self.navigationItem setRightBarButtonItem:rightBarBtn];

}


//实现按键的响应方法

-(void)addVegetables{

    //生成提示框

    UIAlertController* alert=[UIAlertController alertControllerWithTitle:@"增加蔬菜" message:nil preferredStyle:UIAlertControllerStyleAlert];

    _vegController=alert;//赋值

    //增加蔬菜名的输入框

    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull tf){

        tf.placeholder=@"蔬菜名";

        tf.tag=1;

    }];

    //增加菜价输入框

    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull tf1){

        tf1.placeholder=@"价格";

        tf1.tag=2;

    }];

    //增加确认按钮 handler点击确认按钮以后执行的操作

    UIAlertAction* confim=[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        //读取蔬菜名和菜价 调用方法 向数据库中增加蔬菜

        //首先获取输入框 将输入框的内容存成数组

        NSArray* tfs=_vegController.textFields;

        //声明蔬菜的名称和价格

        NSString*vegName1=nil;

        double vegPrice=0;

        //遍历输入框里的内容 获取蔬菜的名称和价格

        for (UITextField* tff in tfs) {

            if (tff.tag==1) {

                vegName1=tff.text;

            }else if (tff.tag==2){

                vegPrice=[tff.text doubleValue];

            }

        }

        //创建蔬菜实例

        Vegetable* vege=[[Vegetable alloc]init];

        vege.name=vegName1;

        vege.price=vegPrice;

        [[Manager sharedInstance]addVegetable:vege];

        [_vegListView reloadData];

        _vegController=nil;

    }];

    //将确认按钮添加到提示框

    [alert addAction:confim];

    

    //增加取消按钮

    UIAlertAction* cancel=[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];

    [alert addAction:cancel];

    

    //显示提示框

    [self presentViewController:alert animated:YES completion:nil];

}


//实现委托代理方法

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

    return 1;

}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    //返回Manager的单例的vagetables数组的count值

    return [[Manager sharedInstance]vagetables].count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    //先获取对应位置的蔬菜实例

    Vegetable* vegetab=[[[Manager sharedInstance]vagetables]objectAtIndex:indexPath.row];

    //完成cell的实例化

    UITableViewCell* vegcell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell1"];

    vegcell.textLabel.text=vegetab.name;

    vegcell.detailTextLabel.text=[NSString stringWithFormat:@"%.2f",vegetab.price];

    return vegcell;

}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}



@end

http://img1.sycdn.imooc.com//climg/5b61743000013bcc07970607.jpg

为什么添加蔬菜失败呢

正在回答

登陆购买课程后可参与讨论,去登陆

7回答

原先代码的基础上在initWithUniqueInstance方法中将如下代码的VVEGETABLES修改成VEGETABLES

char sql_create[1000]="CREATE TABLE VEGETABLES(ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,PRICE REAL)";

另外,先把原先加载的程序在模拟器上删除之后再加载,command+shift+H回到home界面,然后长按删除原先加载的程序,再重新运行。

  • 盛益华通 提问者 #1
    可以了 谢谢老师
    2018-08-03 12:00:49
提问者 盛益华通 2018-08-03 09:42:33

http://img1.sycdn.imooc.com//climg/5b63b2f300019cf413340760.jpg

是的呢老师 修改过了 依然失败

提问者 盛益华通 2018-08-03 08:45:28

http://img1.sycdn.imooc.com//climg/5b63a58200014a8711830825.jpg

表名已经修改了 但是仍然添加失败

  • 昨天调试代码这边检测的error就是表名错误,修改过后,执行程序正常添加蔬菜。表名需要修改的是readVegetableListFromSqlite方法中char sql_read[1000]="SELECT ID,NAME,PRICE FROM VAGETABLES";这句代码中的表名。
    2018-08-03 09:37:57
提问者 盛益华通 2018-08-02 14:00:11
  • 还能继续执行吗
    2018-08-02 14:12:12
  • 提问者 盛益华通 回复 Tender10 #2
    不能了。。
    2018-08-02 14:40:42
  • Tender10 回复 提问者 盛益华通 #3
    在你的Manager类中的readVegetableListFromSqlite方法中创建指令的时候表明写错了,应该是VEGETABLES,你写成了VAGETABLES
    2018-08-02 18:20:50
提问者 盛益华通 2018-08-02 08:56:06

http://img1.sycdn.imooc.com//climg/5b6256700001d16511540914.jpg

可是添加蔬菜一直失败 我反复对过代码 没有找到错误 

  • 你在添加蔬菜的方法,还有检查添加蔬菜方法里都打上断点调试一下,看看断点调试是执行到什么地方出错的。
    2018-08-02 13:47:35
Tender10 2018-08-01 17:41:57

Manager类中的

NSMutableArray* vegeMutableArray=[NSMutableArray alloc];

这句代码修改成

NSMutableArray* vegetablesMutableArray = [NSMutableArray array];


提问者 盛益华通 2018-08-01 17:00:18

#import "Manager.h"

//管理类使用sqlite 所以引入sqlite3库 导入头文件

#import <sqlite3.h>


//类的扩展 增加蔬菜列表属性

@interface Manager()

//创建一个数组类型 存储蔬菜列表

@property(nonatomic,strong)NSArray* vegArray;

@end


@implementation Manager


//实现单例方法

+(instancetype)sharedInstance{

    //首先创建一个static类型的实例

    static Manager* shared=nil;

    static dispatch_once_t onceToken;

    //这个方法的目的是只执行一次下面的代码

    dispatch_once(&onceToken, ^{

        shared =[[super alloc]initWithUniqueInstance];

    });

    //返回shared这个单例的实例

    return  shared;

}

//单例模式的初始化

//初始化方法的作用就是判断当前的沙盒中有没有数据库文件 没有的话就创建数据库文件 增加数据表 表中存储蔬菜列表

//如果有数据库文件 就读取数据库文件 将表中的蔬菜列表读取到vegArray中

-(instancetype)initWithUniqueInstance{

    if (self=[super init]) {

        //进行必要的初始化

        //因为这个类是蔬菜管理类 所以初始化方法中需要读取数据库中的蔬菜列表 所以需要去创建蔬菜列表属性和获取数据库路径

        //获取数据库文件的路径

        NSString* sqlitePath=[self sqlitePath];

        //判断数据库文件是否存在

        BOOL fileExist=[[NSFileManager defaultManager]fileExistsAtPath:sqlitePath];

        if (!fileExist) {

            //数据库文件不存在 则创建数据库文件 并且添加数据表

            //将数据库路径由nsstring类型转化成UTF8String格式的c语言字符串

            const char* sqPath=[sqlitePath UTF8String];

            //声明一个sqlite数据库结构体指针

            sqlite3* vegetableSQ;

            //打开数据库文件 没有则创建 参数1是数据库文件的路径 参数2是数据库文件的地址

            if (sqlite3_open(sqPath, &vegetableSQ)==SQLITE_OK) {

                NSLog(@"数据库文件打开/创建成功");

            }else{

                //数据库文件存在 读取数据库文件

                NSLog(@"数据库文件打开/创建失败");

                return nil;//表示单例创建失败

            }

            //数据库文件打开成功 则创建数据表

            //创建语句

            char sql_create[1000]="CREATE TABLE VVEGETABLES(ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,PRICE REAL)";

            

            //执行语句

            if (sqlite3_exec(vegetableSQ, sql_create, NULL, NULL, NULL)==SQLITE_OK) {

                NSLog(@"创建数据表成功");

                //关闭数据库

                sqlite3_close(vegetableSQ);

            }else{

                //数据库文件打开/创建失败 则数据表也创建失败

                NSLog(@"创建数据表失败");

                //同样关闭数据库

                sqlite3_close(vegetableSQ);

                return nil;//整个单例创建失败

            }

        }else{

            //数据库文件存在 读取数据库文件

            //调用读取数据库文件的方法

            [self readVegetablesListFromSqlite];

        }

    }

    return self;

}

//获取数据库文件路径

-(NSString*)sqlitePath{

    //获取cache文件路径

    NSString* cachePath=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject];

    //拼接数据库文件名 即cache路径+数据库文件路径

    NSString* vegPath=[cachePath stringByAppendingPathComponent:@"VEGETABLES.sqlite"];

    return vegPath;

}

//读取数据库文件

-(void)readVegetablesListFromSqlite{

    //打开数据库文件

    const char* sqPath=[[self sqlitePath] UTF8String];

    //声明一个sqlite数据库结构体指针

    sqlite3* vegetableSQ;

    //打开数据库文件 没有则创建 参数1是数据库文件的路径 参数2是数据库文件的地址

    if (sqlite3_open(sqPath, &vegetableSQ)==SQLITE_OK) {

        NSLog(@"数据库文件打开/创建成功");

    }else{

        //数据库文件存在 读取数据库文件

        NSLog(@"数据库文件打开/创建失败");

        return;

    }

    //读取数据库文件的目的是将数据库文件中的蔬菜信息读取到内存中

    //所以创建可变数据来存储蔬菜信息

    NSMutableArray* vegeMutableArray=[NSMutableArray alloc];

    //声明sqlite3_stmt实例

    sqlite3_stmt* statement;

    //创建指令

    char sql_read[1000]="SELECT ID,NAME,PRICE FROM VAGETABLES";

    //准备sql语句 参数1数据库指针 参数2读取指令 参数3数据长度 参数4statement指针的地址

    sqlite3_prepare_v2(vegetableSQ, sql_read, -1, &statement, NULL);

    //逐行返回数据表中的内容

    while (sqlite3_step(statement)==SQLITE_ROW) {

        //分别读取字段

        NSInteger index = sqlite3_column_int(statement, 0);

        NSString* vegeName=[[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 1)];

        double vegprice = sqlite3_column_double(statement, 2);

        //创建蔬菜类实例 并用从数据表中获取到的name和price来初始化实例

        Vegetable* vegg=[[Vegetable alloc]init];

        vegg.name=vegeName;

        vegg.price=vegprice;

        //将创建的实例添加到数组中

        [vegeMutableArray addObject:vegg];

    }

    NSLog(@"数据库读取完毕");

    //使用copy方法将可变数组中的内容传给不可变数组

    _vegArray=[vegeMutableArray copy];

    //清理内存 关闭数据库

    sqlite3_finalize(statement);

    sqlite3_close(vegetableSQ);

    

}

//返回蔬菜列表

-(NSArray*)vagetables{

    //copy防止篡改

    return [_vegArray copy];

}

//判断蔬菜的名称是否在列表中 对蔬菜进行编辑之前要先判断

-(BOOL)isInListForVegetableName:(NSString*)name{

    //遍历存储蔬菜列表的数组 对名称进行判断

    for (Vegetable* vegs in _vegArray) {

        if ([vegs.name isEqualToString:name]) {

            //名称相同

            return true;

        }

    }

    //名称不同

    return false;

}

//添加蔬菜

-(BOOL)addVegetable:(Vegetable *)veg{

    //先判断想要添加的蔬菜是否存在

    if ([self isInListForVegetableName:veg.name]) {

        NSLog(@"已经存在这个蔬菜");

        return NO;

    }

    //判断输入的蔬菜信息是否有误

    if (veg.name.length==0 || veg.price <=0) {

        NSLog(@"蔬菜信息有误");

        return NO;

    }

    

    //打开数据库文件

    const char* sqPath=[[self sqlitePath] UTF8String];

    //声明一个sqlite数据库结构体指针

    sqlite3* vegetableSQ;

    //打开数据库文件 没有则创建 参数1是数据库文件的路径 参数2是数据库文件的地址

    if (sqlite3_open(sqPath, &vegetableSQ)==SQLITE_OK) {

        NSLog(@"数据库文件打开/创建成功");

    }else{

        //数据库文件存在 读取数据库文件

        NSLog(@"数据库文件打开/创建失败");

        return NO;

    }

    //创建语句

    NSString* add=[NSString stringWithFormat:@"INSERT INTO VEGETABLES (NAME,PRICE) VALUES (\"%@\",%f)",veg.name,veg.price];

    //将语句转化成c语言字符串

    const char* sql_add=[add UTF8String];

    //执行语句

    if (sqlite3_exec(vegetableSQ, sql_add, NULL, NULL, NULL)==SQLITE_OK) {

        NSLog(@"添加蔬菜成功");

        //关闭数据库

        sqlite3_close(vegetableSQ);

        //数据库已更新 再次读取数据库调用方法

        [self readVegetablesListFromSqlite];

        return YES;

    }else{

        NSLog(@"添加蔬菜失败");

        sqlite3_close(vegetableSQ);

        return NO;

    }

}

//删除蔬菜

-(BOOL)removeVegetableWithName:(NSString *)vegName{

    //先判断想要删除的蔬菜是否存在

    if (![self isInListForVegetableName:vegName]) {

        NSLog(@"找不到要删除的蔬菜");

        return NO;

    }

    

    //打开数据库文件

    const char* sqPath=[[self sqlitePath] UTF8String];

    //声明一个sqlite数据库结构体指针

    sqlite3* vegetableSQ;

    //打开数据库文件 没有则创建 参数1是数据库文件的路径 参数2是数据库文件的地址

    if (sqlite3_open(sqPath, &vegetableSQ)==SQLITE_OK) {

        NSLog(@"数据库文件打开/创建成功");

    }else{

        //数据库文件存在 读取数据库文件

        NSLog(@"数据库文件打开/创建失败");

        return NO;

    }

    //创建语句

    NSString* delete=[NSString stringWithFormat:@"DELETE FROM VEGETABLES WHERE NAME = \"%@\"",vegName];

    //将语句转化成c语言字符串

    const char* sql_delete=[delete UTF8String];

    //执行语句

    if (sqlite3_exec(vegetableSQ, sql_delete, NULL, NULL, NULL)==SQLITE_OK) {

        NSLog(@"删除蔬菜成功");

        //关闭数据库

        sqlite3_close(vegetableSQ);

        //数据库已更新 再次读取数据库调用方法

        [self readVegetablesListFromSqlite];

        return YES;

    }else{

        NSLog(@"删除蔬菜失败");

        sqlite3_close(vegetableSQ);

        return NO;

    }

}


//修改蔬菜价格

-(BOOL)changePrice:(double)vegPrice forVegetableName:(NSString *)vegName2{

    //先判断想要修改的蔬菜是否存在

    if (![self isInListForVegetableName:vegName2]) {

        NSLog(@"找不到要修改的蔬菜");

        return NO;

    }

    

    //打开数据库文件

    const char* sqPath=[[self sqlitePath] UTF8String];

    //声明一个sqlite数据库结构体指针

    sqlite3* vegetableSQ;

    //打开数据库文件 没有则创建 参数1是数据库文件的路径 参数2是数据库文件的地址

    if (sqlite3_open(sqPath, &vegetableSQ)==SQLITE_OK) {

        NSLog(@"数据库文件打开/创建成功");

    }else{

        //数据库文件存在 读取数据库文件

        NSLog(@"数据库文件打开/创建失败");

        return NO;

    }

    //创建语句

    NSString* update=[NSString stringWithFormat:@"UPDATE VEGETABLES SET PRICE=%lf WHERE NAME= \"%@\"",vegPrice,vegName2];

    //将语句转化成c语言字符串

    const char* sql_update=[update UTF8String];

    //执行语句

    if (sqlite3_exec(vegetableSQ, sql_update, NULL, NULL, NULL)==SQLITE_OK) {

        NSLog(@"修改蔬菜成功");

        //关闭数据库

        sqlite3_close(vegetableSQ);

        //数据库已更新 再次读取数据库调用方法

        [self readVegetablesListFromSqlite];

        return YES;

    }else{

        NSLog(@"修改蔬菜失败");

        sqlite3_close(vegetableSQ);

        return NO;

    }

}

@end

这是管理文件类的代码

问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
iOS进阶:界面优化与数据存储
  • 参与学习       516    人
  • 提交作业       158    份
  • 解答问题       637    个

本路径采用基础+案例方式,助你解开对界面优化、数据储存、屏幕适配的疑惑。6小时团购项目实战加最新版本Swift讲解,让你掌握更多iOS开发技巧。

了解课程
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师