蔬菜报价表
#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
为什么添加蔬菜失败呢
正在回答
原先代码的基础上在initWithUniqueInstance方法中将如下代码的VVEGETABLES修改成VEGETABLES
char sql_create[1000]="CREATE TABLE VEGETABLES(ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,PRICE REAL)";
另外,先把原先加载的程序在模拟器上删除之后再加载,command+shift+H回到home界面,然后长按删除原先加载的程序,再重新运行。
#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
这是管理文件类的代码
- 参与学习 516 人
- 提交作业 158 份
- 解答问题 637 个
本路径采用基础+案例方式,助你解开对界面优化、数据储存、屏幕适配的疑惑。6小时团购项目实战加最新版本Swift讲解,让你掌握更多iOS开发技巧。
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星