iOS开发实战-时光记账Demo 本地数据库版

来源:互联网 发布:淘宝成都服装出租 编辑:程序博客网 时间:2024/05/23 19:39

现在记账APP也是用途比较广泛 自己写了个简单的demo 欢迎指正

效果

效果.gif

分析

1.思维推导

首先简单的做了下思维推导 思维推导

2.文件结构

大致框架想好后就可以着手开始准备了

  • 数据库管理:coreData
  • 视图管理:navigationcontroller 暂时没有使用cocoapods导入第三方的数据库管理框架 简单的coreData完全可以胜任 说白了就两个页面 主界面 和 记账界面

这是完成时的文件结构 文件结构

3.数据库设计

  • Tally 账单表
  • identity :String 唯一标识
  • expenses :double 支出
  • income :double 收入
  • timestamp :date 时间戳
  • 关系
  • 与TallyDate 日期表:1V1
  • 与TallyType 类型表:1V1 账单表
  • TallyDate 日期表
  • date :string 日期
  • 关系 -与Tally 账单表:1VN 日期表
  • TallyType 类型表
  • typename :string 类型名
  • typeicon :string 类型图片标
  • 关系 -与Tally 账单表:1VN 类型表

4.页面编写

增加账单页面

由于主页只是一个展示的时光轴界面,UIScrollView加几个按钮就能完成,需要读取数据库内容,所以我们先把内页-增加账单 完成。

  • view
  • UICollectionView展示账单类型
  • 自定义View计算器界面计算存储结果
  • model
  • UICollectionViewCell模型 使用了plist和KVC转字典
  • controller
  • 负责添加 两个view 及处理两个view的代理

增加账单部分代码

  • model
#import <Foundation>@interface TallyListCellModel : NSObject@property (nonatomic,copy)NSString *tallyCellImage;@property (nonatomic,copy)NSString *tallyCellName;- (instancetype)initWithDict:(NSDictionary*)dict;+ (instancetype)tallyListCellModelWithDict:(NSDictionary*)dict;@end
#import "TallyListCellModel.h"@implementation TallyListCellModel- (instancetype)initWithDict:(NSDictionary*)dict {    self = [super init];    if (self) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}+ (instancetype)tallyListCellModelWithDict:(NSDictionary*)dict {    return [[TallyListCellModel alloc] initWithDict:dict];}@end
  • 计算界面
#import <UIKit>#import "AppDelegate.h"#import <CoreData>#import "TimeTallyDemo+CoreDataModel.h"typedef void(^PositionInViewBlock)(CGPoint point);@protocol CalculatorViewDelegate <NSObject>//保存成功- (void)tallySaveCompleted;//保存失败- (void)tallySaveFailed;//回到原来的位置- (void)backPositionWithAnimation;@end@interface CalculatorView : UIView//类型图片的size@property(nonatomic,assign)CGSize imageViewSize;//类型图@property(nonatomic,strong)UIImage *image;//类型名@property(nonatomic,strong)NSString *typeName;//账单是否存在 判断 是修改还是新增@property(nonatomic,assign)BOOL isTallyExist;@property(nonatomic,strong)id<CalculatorViewDelegate> delegate;//回调image在整个view中的位置@property(nonatomic,copy)PositionInViewBlock positionInViewBlock;//修改账单界面进入时传入参数- (void)modifyTallyWithIdentity:(NSString *)identity;@end
#import "CalculatorView.h"@interface CalculatorView()@property (nonatomic,assign)CGFloat btnWidth;               //btn宽@property (nonatomic,assign)CGFloat btnHeight;              //btn高@property (nonatomic,copy)NSString *nValue;                 //当前输入值@property (nonatomic,copy)NSString *resutlStr;              //结果值@property (nonatomic,strong)UILabel *resultLab;             //结果栏@property (nonatomic,strong)UIButton *addBtn;               //+@property (nonatomic,strong)UIColor *btnColor;              //按钮颜色@property (nonatomic,assign)CGColorRef boardLineColor;      //边框线条颜色@property (nonatomic,strong)UIImageView *imageView;         //tally类型图@property(nonatomic,strong)UILabel *typeLab;@property(nonatomic,copy)NSString *tallyIdentity;@endstatic CGFloat const kBoardWidth = 1;static CGFloat const kMaxCalCount = 9;@implementation CalculatorView- (instancetype)initWithFrame:(CGRect)frame {    self = [super initWithFrame:frame];    if (self) {        self.backgroundColor = [UIColor whiteColor];        self.btnWidth = (self.frame.size.width-kBoardWidth/2)/4;        self.btnHeight = self.frame.size.height/5;        self.nValue = @"";        self.resutlStr = @"";        self.typeLab.text = @"";        self.btnColor = [UIColor grayColor];        self.boardLineColor = [UIColor lightGrayColor].CGColor;        self.layer.borderColor = self.boardLineColor;        self.layer.borderWidth = kBoardWidth;        self.imageView = [[UIImageView alloc] init];        [self addSubview:self.imageView];        [self loadBtn];    }    return self;}- (void)setImage:(UIImage *)image {    _image = image;    [NSTimer scheduledTimerWithTimeInterval:1 repeats:NO block:^(NSTimer * _Nonnull timer) {        _imageView.image = image;    }];}- (void)setTypeName:(NSString *)typeName {    _typeName = typeName;    self.typeLab.text = typeName;}- (void)setImageViewSize:(CGSize)imageViewSize {    _imageViewSize = imageViewSize;    _imageView.frame = CGRectMake(10, (self.btnHeight-imageViewSize.height)/2, imageViewSize.width, imageViewSize.height);    _imageView.backgroundColor = [UIColor clearColor];    //回调实际位置    if (_positionInViewBlock) {        CGPoint point = CGPointMake(10+imageViewSize.width/2, self.frame.origin.y + _imageView.frame.origin.y + imageViewSize.height/2) ;        _positionInViewBlock(point);    }    self.typeLab.frame = CGRectMake(self.imageView.frame.origin.x + self.imageView.frame.size.width + 10, self.imageView.frame.origin.y, imageViewSize.width * 2, imageViewSize.height);}//类型名称lab- (UILabel *)typeLab {    if (!_typeLab) {        _typeLab = [[UILabel alloc] init];        _typeLab.font = [UIFont systemFontOfSize:14];        [self addSubview:_typeLab];    }    return _typeLab;}//结果lab- (UILabel *)resultLab {    if (!_resultLab) {        _resultLab = [[UILabel alloc] initWithFrame:CGRectMake(self.frame.size.width * 0.3, 0, self.frame.size.width * 0.7-10, self.btnHeight)];        _resultLab.text = @"¥ 0.00";        _resultLab.textAlignment = NSTextAlignmentRight;        _resultLab.adjustsFontSizeToFitWidth = YES;        _resultLab.font = [UIFont systemFontOfSize:25];        _resultLab.userInteractionEnabled = YES;        UITapGestureRecognizer *tag = [[UITapGestureRecognizer alloc] init];        tag.numberOfTapsRequired = 1;        [tag addTarget:self action:@selector(clickResultLab)];        [_resultLab addGestureRecognizer:tag];    }    return _resultLab;}- (void)clickResultLab {    if ([self.delegate respondsToSelector:@selector(backPositionWithAnimation)]) {        [self.delegate backPositionWithAnimation];    }}//加号- (UIButton *)addBtn {    if (!_addBtn) {        ...        [_addBtn addTarget:self action:@selector(clickAdd) forControlEvents:UIControlEventTouchUpInside];    }    return _addBtn;}//普通数字btn- (void)loadBtn {    // 1 - 9 btn    ...    [btn addTarget:self action:@selector(clickNumber:) forControlEvents:UIControlEventTouchUpInside];    //0 btn    ...    [zeroBtn addTarget:self action:@selector(clickNumber:) forControlEvents:UIControlEventTouchUpInside];    //小数点 btn    ...    pointBtn.tag = 99;    [pointBtn addTarget:self action:@selector(clickNumber:)     //重置 btn    ...    [resetBtn addTarget:self action:@selector(resetZero) forControlEvents:UIControlEventTouchUpInside];      //DEL btn    ...    [delBtn addTarget:self action:@selector(clickDel) forControlEvents:UIControlEventTouchUpInside];    //ok btn    ...    [okBtn addTarget:self action:@selector(clickOk) forControlEvents:UIControlEventTouchUpInside];    [self addSubview:self.addBtn];    [self addSubview:self.resultLab];}//点击数字按键- (void)clickNumber:(UIButton*)btn {    if(self.addBtn.isSelected){        self.nValue = @"";    }    NSString *currentValue = @"";    if (btn.tag == 99) {        //有 . 就不加 .        if ([self.nValue rangeOfString:@"."].location == NSNotFound) {            currentValue = @".";        }    }else {        currentValue = [NSString stringWithFormat:@"%ld",(long)btn.tag];    }    self.nValue = [self.nValue stringByAppendingString:currentValue];    //保留小数点后两位    NSRange pointRange = [self.nValue rangeOfString:@"."];    if (pointRange.location != NSNotFound) {        if ([self.nValue substringFromIndex:pointRange.location+1].length > 2) {            self.nValue = [self.nValue substringWithRange:NSMakeRange(0, pointRange.location + 3)];        }        //总位数不超过9 处理小数部分        if ([self.nValue substringToIndex:pointRange.location].length > kMaxCalCount) {            self.nValue = [NSString stringWithFormat:@"%0.2f",[self.nValue doubleValue]];            self.nValue = [self.nValue substringToIndex:kMaxCalCount+3];        }    } else {        //总位数不超过9 整数部分        if (self.nValue.length > kMaxCalCount) {            self.nValue = [NSString stringWithFormat:@"%0.2f",[self.nValue doubleValue]];            self.nValue = [self.nValue substringToIndex:kMaxCalCount];        }    }    //显示数字    self.resultLab.text = [NSString stringWithFormat:@"¥ %.2f",[self.nValue doubleValue]];    self.addBtn.selected = NO;    NSLog(@"new = %@",self.nValue);}//单击加号- (void)clickAdd {    //显示结果  点击后nValue清零    if (!self.addBtn.isSelected) {        self.addBtn.selected = YES;        double result = [self.resutlStr doubleValue] + [self.nValue doubleValue] ;        self.resutlStr = [NSString stringWithFormat:@"%.2f",result];        self.resultLab.text = [NSString stringWithFormat:@"¥ %.2f",[self.resutlStr doubleValue]];        NSLog(@"resutl = %@",self.resutlStr);    }}//重置0- (void)resetZero {    self.resutlStr = @"";    self.nValue = @"";    self.resultLab.text = @"¥ 0.00";}//退格- (void)clickDel {    if (self.nValue.length > 0) {        self.nValue = [self.nValue substringWithRange:NSMakeRange(0, self.nValue.length-1)];    }    NSLog(@"-----%@",self.nValue);    self.resultLab.text = [NSString stringWithFormat:@"¥ %.2f",[self.nValue doubleValue]];}//完成- (void)clickOk {    //存在 使用修改保存方式 不存在 使用新增保存方式    if (self.isTallyExist) {        [self modifyTallySavedWithIdentity:self.tallyIdentity];    } else {        [self addTallySave];    }}//增加账单保存- (void)addTallySave {    if ( ![self.typeLab.text isEqualToString:@""] && [self.nValue doubleValue] != 0) {        [self clickAdd];        //存数据        NSManagedObjectContext *managedObjectContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];        [dateFormatter setDateFormat:@"yyyy-MM-dd"];        NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];        //查询有无对应的date 有则使用无则创建        NSFetchRequest *fdate = [TallyDate fetchRequest];        NSArray<NSSortDescriptor> *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:YES]];        fdate.sortDescriptors = sortDescriptors;        NSPredicate *p = [NSPredicate predicateWithFormat:@"date = %@",dateString];        fdate.predicate = p;        NSArray<TallyDate> *ss = [managedObjectContext executeFetchRequest:fdate error:nil];        TallyDate *date;        if (ss.count > 0) {            date = ss[0];        } else {            date = [[TallyDate alloc] initWithContext:managedObjectContext];            date.date = dateString;        }        //配置数据        Tally *model = [[Tally alloc] initWithContext:managedObjectContext];        NSFetchRequest *ftype = [TallyType fetchRequest];        NSPredicate *ptype = [NSPredicate predicateWithFormat:@"typename = %@",self.typeLab.text];        ftype.predicate = ptype;        NSArray<TallyType> *sstype = [managedObjectContext executeFetchRequest:ftype error:nil];        TallyType *type = [sstype firstObject];        //给关系赋值        model.typeship = type;        model.dateship = date;        model.identity = [NSString stringWithFormat:@"%@", [model objectID]];        model.timestamp = [NSDate date];        if ([self.typeLab.text isEqualToString:@"工资"]) {            model.income = [self.resutlStr doubleValue];            model.expenses = 0;        } else {            model.expenses = [self.resutlStr doubleValue];            model.income = 0;        }        //存        [managedObjectContext save:nil];        if ([self.delegate respondsToSelector:@selector(tallySaveCompleted)]) {            [self.delegate tallySaveCompleted];        }    } else {        if ([self.delegate respondsToSelector:@selector(tallySaveFailed)]) {            [self.delegate tallySaveFailed];        }        NSLog(@"不存");    }}//修改账单保存- (void)modifyTallySavedWithIdentity:(NSString *)identity {    [self clickAdd];       if ([self.resutlStr doubleValue] == 0) {        if ([self.delegate respondsToSelector:@selector(tallySaveFailed)]) {            [self.delegate tallySaveFailed];        }        NSLog(@"不存");        return;    }    self.addBtn.selected = NO;    NSManagedObjectContext *managedObjectContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;    //设置账单类型    NSFetchRequest *ftype = [TallyType fetchRequest];    NSPredicate *ptype = [NSPredicate predicateWithFormat:@"typename = %@",self.typeLab.text];    ftype.predicate = ptype;    NSArray<TallyType> *sstype = [managedObjectContext executeFetchRequest:ftype error:nil];    TallyType *type = [sstype firstObject];    //找出当前账单    NSFetchRequest *fetchRequest = [Tally fetchRequest];    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"identity = %@", identity];    [fetchRequest setPredicate:predicate];    NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];    //配置当前账单    Tally *tally = [fetchedObjects firstObject];    tally.typeship = type;    if ([self.typeLab.text isEqualToString:@"工资"]) {        tally.income = [self.resutlStr doubleValue];        tally.expenses = 0;    } else {        tally.expenses = [self.resutlStr doubleValue];        tally.income = 0;    }    [managedObjectContext save:nil];    if ([self.delegate respondsToSelector:@selector(tallySaveCompleted)]) {        [self.delegate tallySaveCompleted];    }}//修改界面传值- (void)modifyTallyWithIdentity:(NSString *)identity {    self.tallyIdentity = identity;    NSManagedObjectContext *managedObjectContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;    NSFetchRequest *fetchRequest = [Tally fetchRequest];    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"identity = %@", identity];    [fetchRequest setPredicate:predicate];    NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];    Tally *tally = [fetchedObjects firstObject];    self.imageView.image = [UIImage imageNamed:tally.typeship.typeicon];    self.typeLab.text = tally.typeship.typename;    self.nValue = tally.income > 0?[NSString stringWithFormat:@"%@",@(tally.income)]:[NSString stringWithFormat:@"%@",@(tally.expenses)];    self.resultLab.text = [NSString stringWithFormat:@"¥ %.2f",[self.nValue doubleValue]];    self.isTallyExist = YES;}@end
  • 类型选择界面 自定义cell就不贴出来了 就一个图片和label
#import <UIKit>#import "TallyListCell.h"#import <CoreData>#import "TimeTallyDemo+CoreDataModel.h"#import "AppDelegate.h"@protocol TallyListViewDelegate <NSObject>//选择对应cell 传递 image title cell的实际位置- (void)didSelectItem:(UIImage*)cellImage andTitle:(NSString*)title withRectInCollection:(CGRect)itemRect;//滚动到底- (void)listScrollToBottom;@end@interface TallyListView : UICollectionView@property(nonatomic,strong)id<TallyListViewDelegate> customDelegate;@end
#import "TallyListView.h"@interface TallyListView()<UICollectionViewDelegate>@property (nonatomic, strong) NSArray *tallyListArray;@property (nonatomic, assign) CGFloat offsety;@endstatic NSString *cellId = @"tallyListCellID";@implementation TallyListView//读取plist数据- (NSArray *)tallyListArray {    if (!_tallyListArray) {        NSMutableArray *res = [NSMutableArray array];        NSString *path = [[NSBundle mainBundle] pathForResource:@"TallyList" ofType:@"plist"];        NSArray *list = [NSArray arrayWithContentsOfFile:path];        for (NSDictionary *dict in list) {            TallyListCellModel *model = [TallyListCellModel tallyListCellModelWithDict:dict];            [res addObject:model];        }        _tallyListArray = [NSArray arrayWithArray:res];        [self writeToSqlite];    }    return  _tallyListArray;}- (void)writeToSqlite {    //将类型名字和图片信息写入数据库    NSManagedObjectContext *managedObjectContext = ((AppDelegate*)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;    for (TallyListCellModel *model in self.tallyListArray) {        //查询有无对应的type 有则使用无则创建        NSFetchRequest *fdate = [TallyType fetchRequest];        NSPredicate *p = [NSPredicate predicateWithFormat:@"typename = %@",model.tallyCellName];        fdate.predicate = p;        NSArray<TallyType> *ss = [managedObjectContext executeFetchRequest:fdate error:nil];        if (ss.count == 0) {            TallyType *type = [[TallyType alloc] initWithContext:managedObjectContext];            type.typename = model.tallyCellName;            type.typeicon = model.tallyCellImage;            [managedObjectContext save:nil];        }    }}//初始化- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {    self = [super initWithFrame:frame collectionViewLayout:layout];    if (self) {        self.delegate = self;        self.dataSource = self;        self.backgroundColor = [UIColor clearColor];        [self registerNib:[UINib nibWithNibName:@"TallyListCell" bundle:nil] forCellWithReuseIdentifier:cellId];         }    return self;}#pragma mark - UICollectionViewDelegate & UICollectionViewDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return self.tallyListArray.count;}- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    TallyListCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];    cell.cellModel = self.tallyListArray[indexPath.item];    return cell;}- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {    TallyListCell *cell = (TallyListCell*)[collectionView cellForItemAtIndexPath:indexPath];    //cell在collectionView的位置    CGRect cellRect = [collectionView convertRect:cell.frame fromView:collectionView];    //image在cell中的位置    CGRect imgInCellRect = cell.imageView.frame;    CGFloat x = cellRect.origin.x + imgInCellRect.origin.x;    CGFloat y = cellRect.origin.y + imgInCellRect.origin.y + 64 - self.offsety;    //图片在collectionView的位置    CGRect imgRect = CGRectMake(x, y, imgInCellRect.size.width, imgInCellRect.size.height);    //回调    if ([self.customDelegate respondsToSelector:@selector(didSelectItem:andTitle:withRectInCollection:)]){        [self.customDelegate didSelectItem:cell.imageView.image andTitle:cell.imageLab.text withRectInCollection:imgRect];    }}//外部调用 用于修改账单传值- (void)scrollViewDidScroll:(UIScrollView *)scrollView {    self.offsety = scrollView.contentOffset.y;}- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{    CGFloat bottomY = self.contentSize.height - self.frame.size.height;    if (scrollView.contentOffset.y >= bottomY) {        NSLog(@"计算器下去");        if ([self.customDelegate respondsToSelector:@selector(listScrollToBottom)]) {            [self.customDelegate listScrollToBottom];        }    }}@end

主页面界面

  • model
  • 用于传递给账单界面的数据模型
  • view
  • 时间线绘图
  • controller
  • 处理时间线视图的删改查

主界面部分代码

  • model
#import <Foundation>typedef enum : NSUInteger {    TallyMoneyTypeIn = 0,    TallyMoneyTypeOut,} TallyMoneyType;@interface TimeLineModel : NSObject@property(nonatomic,copy)NSString *tallyIconName;@property(nonatomic,assign)double tallyMoney;@property(nonatomic,assign)TallyMoneyType tallyMoneyType;@property(nonatomic,copy)NSString *tallyDate;@property(nonatomic,copy)NSString *tallyType;@property(nonatomic,copy)NSString *identity;@property(nonatomic,assign)double income;@property(nonatomic,assign)double expense;@end
  • 时间线视图 这里用runtime方法为uibutton分类给时间线上的btn添加了两个属性 keyWithBtn :用于存储日期 panelBtnType :用于存储按钮是修改还是删除
typedef enum : NSUInteger {    PanelViewBtnTypeLeft = 0,    PanelViewBtnTypeRight,} PanelViewBtnType;//使用runtime 给uibutton扩展 属性@interface UIButton (BtnWithKey)@property(nonatomic,copy)NSString *keyWithBtn;@property(nonatomic,assign)PanelViewBtnType panelBtnType;@endstatic const void *kKeyWithBtn = @"keyWithBtn";static const void *kPanelBtnType = @"panelBtnType";@implementation UIButton (BtnWithKey)- (NSString *)keyWithBtn {    return objc_getAssociatedObject(self, kKeyWithBtn);}- (void)setKeyWithBtn:(NSString *)keyWithBtn {    objc_setAssociatedObject(self, kKeyWithBtn, keyWithBtn, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (PanelViewBtnType)panelBtnType {    return [objc_getAssociatedObject(self, kPanelBtnType) intValue];}- (void)setPanelBtnType:(PanelViewBtnType)panelBtnType {    objc_setAssociatedObject(self, kPanelBtnType, [NSNumber numberWithUnsignedInteger:panelBtnType], OBJC_ASSOCIATION_RETAIN_NONATOMIC);}@end
#import "TimeLineView.h"@interface TimeLineView()@property(nonatomic,strong)UIView *panelView;       //删除、修改 面板@end@implementation TimeLineView- (instancetype)initWithFrame:(CGRect)frame {    self = [super initWithFrame:frame];    if (self) {    }    return self;}- (void)drawRect:(CGRect)rect {    CGContextRef context = UIGraphicsGetCurrentContext();    int keyIndex = 0;    CGFloat aDateAllLine = 0;    for (NSString *key  in self.timeLineModelsDict.allKeys) {        //读取字典对应key的数组        NSArray<TimeLineModel> *modelArray = self.timeLineModelsDict[key];        //画线画日期        CGRect dateRect = CGRectMake(self.center.x-kDateWidth/2, aDateAllLine, kDateWidth, kDateWidth);        CGContextAddEllipseInRect(context, dateRect);        CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);        CGContextFillPath(context);        CGContextStrokePath(context);        CGRect dateLabRect = CGRectMake(0, aDateAllLine, self.frame.size.width/2-kBtnWidth, kBtnWidth/2);        //日期lab        UILabel *dateLab = [[UILabel alloc] initWithFrame:dateLabRect];        dateLab.textAlignment = NSTextAlignmentRight;        dateLab.text = key;        [dateLab setTextColor:[UIColor blueColor]];        [self addSubview:dateLab];        for (int i = 0 ; i < modelArray xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed>*array = self.timeLineModelsDict[btn.keyWithBtn];        [self.delegate willDeleteCurrentTallyWithIdentity:array[btn.tag].identity];    }}//修改当前账单  回调给controller处理- (void)modifyCurrentTally:(UIButton*)btn {    if ([self.delegate respondsToSelector:@selector(willModifyCurrentTallyWithIdentity:)]) {        NSArray<TimeLineModel>*array = self.timeLineModelsDict[btn.keyWithBtn];        [self.delegate willModifyCurrentTallyWithIdentity:array[btn.tag].identity];    }}@end
  • controller
#import "ViewController.h"#import "AddTallyViewController.h"#import "TimeLineView.h"@interface ViewController ()<TimeLineViewDelegate>@property(nonatomic,strong)UIScrollView *scrollView;@property(nonatomic,strong)NSDictionary *timeLineModelsDict;@property(nonatomic,assign)CGFloat allDateAllLine;@property (weak, nonatomic) IBOutlet UILabel *incomLab;@property (weak, nonatomic) IBOutlet UILabel *expenseLab;@end@implementation ViewController- (UIScrollView *)scrollView {    if (!_scrollView) {         _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64+80, self.view.frame.size.width, self.view.frame.size.height-64-80)];        _scrollView.backgroundColor = [UIColor whiteColor];    }    return _scrollView;}- (void)viewDidLoad {    [super viewDidLoad];    NSLog(@"%@",NSHomeDirectory());    self.title = @"我的账本";    [self.view addSubview:self.scrollView];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}//增加一条账单- (IBAction)clickAddTally:(id)sender {    AddTallyViewController *addVC = [[AddTallyViewController alloc] init];    [self.navigationController pushViewController:addVC animated:YES];}//出现时 刷新整个时间线- (void)viewWillAppear:(BOOL)animated {    NSLog(@"will");    [self showTimeLineView];}- (void)showTimeLineView {    //先读取数据库中内容 封装成字典    [self readSqliteData];    //移除上一个timelineView    for (UIView *view in self.scrollView.subviews) {        if (view.tag == 1990) {            [view removeFromSuperview];        }    }    //计算总收入 和 总支出    double incomeTotal = 0;    double expenseTotal = 0;    self.allDateAllLine = 0;    //计算时间线长度    for (NSString *key  in self.timeLineModelsDict.allKeys) {        NSArray<TimeLineModel> *modelArray = self.timeLineModelsDict[key];        //一天的时间线总长        self.allDateAllLine = self.allDateAllLine + kDateWidth + (kBtnWidth+kLineHeight)*modelArray.count + kLineHeight;        for (TimeLineModel *model in modelArray) {            incomeTotal = incomeTotal + model.income;            expenseTotal = expenseTotal + model.expense;        }    }    self.incomLab.text = [NSString stringWithFormat:@"%.2f",incomeTotal];    self.expenseLab.text = [NSString stringWithFormat:@"%.2f",expenseTotal];    //设置时间线视图timelineview    CGRect rect  = CGRectMake(0, 0, self.view.frame.size.width, self.allDateAllLine);    TimeLineView *view = [[TimeLineView alloc] initWithFrame:rect];    view.tag = 1990;    view.delegate = self;    view.backgroundColor = [UIColor whiteColor];    view.timeLineModelsDict = self.timeLineModelsDict;    [self.scrollView addSubview:view];    self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.allDateAllLine);    //滚动到顶端    [self.scrollView setContentOffset:CGPointZero animated:YES];}//读取数据库中的数据  以字典的形式 key:@"日期" object:[账单信息]- (void)readSqliteData{    NSManagedObjectContext *managedObjectContext = ((AppDelegate*)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;    self.timeLineModelsDict = nil;    //先查询日期 遍历日期表    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];    NSEntityDescription *entity = [NSEntityDescription entityForName:@"TallyDate" inManagedObjectContext:managedObjectContext];    [fetchRequest setEntity:entity];    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];    NSError *error = nil;    NSArray<TallyDate> *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];    NSMutableDictionary *dict = [NSMutableDictionary dictionary];    //再查询该日期下的tally表    for (TallyDate *date in fetchedObjects) {        NSString *key = date.date;        NSFetchRequest *fetchRequest2 = [[NSFetchRequest alloc] init];        NSEntityDescription *entity2 = [NSEntityDescription entityForName:@"Tally" inManagedObjectContext:managedObjectContext];        [fetchRequest2 setEntity:entity2];        //在tally表中 筛选 为该日期的tally 并逆序排列        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dateship.date = %@",key];        [fetchRequest2 setPredicate:predicate];        NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:NO];        [fetchRequest2 setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor2, nil]];        NSError *error = nil;        NSArray<Tally> *fetchedObjects2 = [managedObjectContext executeFetchRequest:fetchRequest2 error:&error];        NSMutableArray *array = [NSMutableArray array];        //遍历 tally表 将表中的每个结果保存下来        for (Tally *tally in fetchedObjects2) {            TimeLineModel *model = [[TimeLineModel alloc] init];            model.tallyDate = tally.dateship.date;            model.tallyIconName = tally.typeship.typeicon;            model.tallyMoney = tally.income > 0 ? tally.income:tally.expenses;            model.tallyMoneyType = tally.income > 0 ? TallyMoneyTypeIn:TallyMoneyTypeOut;            model.tallyType = tally.typeship.typename;            model.identity = tally.identity;            model.income = tally.income;            model.expense = tally.expenses;            [array addObject:model];        }        [dict setObject:array forKey:key];    }    self.timeLineModelsDict = dict;}//删除前的确认- (void)willDeleteCurrentTallyWithIdentity:(NSString*)identity {    UIAlertController *alertVC =[UIAlertController alertControllerWithTitle:@"提示" message:@"确认删除" preferredStyle:UIAlertControllerStyleAlert ];    [alertVC addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        //从数据库中删除 Tally表中对应identity字段行        NSManagedObjectContext *managedObjectContext = ((AppDelegate*)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;        NSFetchRequest *fetchRequest = [Tally fetchRequest];        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"identity = %@", identity];        [fetchRequest setPredicate:predicate];        NSError *error = nil;        NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];        [managedObjectContext deleteObject:[fetchedObjects firstObject]];        [managedObjectContext save:&error];        //删除完成后 刷新视图        [self showTimeLineView];    }]];    [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];    [self presentViewController:alertVC animated:YES completion:nil];}//TimeLineViewDelegate  delegate 修改前的准备- (void)willModifyCurrentTallyWithIdentity:(NSString*)identity {    AddTallyViewController *addVC = [[AddTallyViewController alloc] init];    [addVC selectTallyWithIdentity:identity];    [self.navigationController pushViewController:addVC animated:YES];}@end

5.结束

由于coredata增删改查时的代码量实在是太大,我们可以优化一下,将数据库操作全部放到一个类中,这样代码逻辑会更清晰一点,可读性更强。 也是也到这里才想到数据库封装。所以刚刚去改了下。 所以上面的代码都包括冗长的coreData操作

创建一个 数据库操作的单例

#import <Foundation>#import <CoreData>#import "TimeTallyDemo+CoreDataModel.h"#import "AppDelegate.h"#import "TimeLineModel.h"@interface CoreDataOperations : NSObject@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;//单例+ (instancetype)sharedInstance;//从数据库中删除 Tally表中对应identity字段行- (void)deleteTally:(Tally*)object;//保存- (void)saveTally;//读取对应字段- (Tally*)getTallyWithIdentity:(NSString *)identity;//获取对应类型- (TallyType*)getTallyTypeWithTypeName:(NSString*)typeName;//读取数据库中的数据  以字典的形式 key:@"日期" object:[账单信息]- (NSDictionary*)getAllDataWithDict;@end
#import "CoreDataOperations.h"@interface CoreDataOperations()@end@implementation CoreDataOperationsstatic CoreDataOperations *instance = nil;+ (instancetype)sharedInstance{    return [[CoreDataOperations alloc] init];}+ (instancetype)allocWithZone:(struct _NSZone *)zone{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        instance = [super allocWithZone:zone];    });    return instance;}- (instancetype)init{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        instance = [super init];        if (instance) {            instance.managedObjectContext = ((AppDelegate*)[UIApplication sharedApplication].delegate).persistentContainer.viewContext;        }    });    return instance;}//从数据库中删除 Tally表中某一数据- (void)deleteTally:(Tally*)object {    [self.managedObjectContext deleteObject:object];}//保存- (void)saveTally {    [self.managedObjectContext save:nil];}//读取对应字段- (Tally*)getTallyWithIdentity:(NSString *)identity {    //返回对应账单}//获取对应类型- (TallyType*)getTallyTypeWithTypeName:(NSString*)typeName {    //返回对应账单类型}//读取数据库中的数据  以字典的形式 key:@"日期" object:[账单信息]- (NSDictionary*)getAllDataWithDict{        //遍历查询    return dict;}@end

Demo地址

欢迎加星关注 https://github.com/gongxiaokai/TimeTallyDemo 简书地址http://www.jianshu.com/u/7897b0bd4a55


0 0
原创粉丝点击