├── Calculator1.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── ruru.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcdebugger │ │ └── Expressions.xcexplist └── xcuserdata │ └── ruru.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── Calculator1.xcscheme │ └── xcschememanagement.plist ├── Calculator1 ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── 11.imageset │ │ ├── 11.jpeg │ │ └── Contents.json │ ├── 33.imageset │ │ ├── 33.jpeg │ │ └── Contents.json │ ├── 44.imageset │ │ ├── 44.jpeg │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon副本.png │ │ └── 图标.png │ ├── Contents.json │ ├── back-1.imageset │ │ ├── Contents.json │ │ └── back.jpg │ ├── back.imageset │ │ ├── Contents.json │ │ └── back.png │ ├── back_ocean.imageset │ │ ├── 1358750368853.png │ │ └── Contents.json │ ├── back_red.imageset │ │ ├── 1426583873861.jpg │ │ └── Contents.json │ ├── back_sky_dark.imageset │ │ ├── Contents.json │ │ └── af42ed5ad1574e94b9b869613d6dc658.jpg │ ├── back_sky_yellow.imageset │ │ ├── 141146361770.jpg │ │ └── Contents.json │ ├── back_sunshine.imageset │ │ ├── 1411463611130.jpg │ │ └── Contents.json │ ├── next.imageset │ │ ├── Contents.json │ │ └── next.png │ ├── ok.imageset │ │ ├── Contents.json │ │ └── ok.png │ ├── ok11.imageset │ │ ├── Contents.json │ │ └── ok.png │ ├── set1.imageset │ │ ├── Contents.json │ │ └── set1.png │ ├── set2.imageset │ │ ├── Contents.json │ │ └── set2.png │ ├── setting.imageset │ │ ├── Contents.json │ │ └── setting.png │ ├── setting1.imageset │ │ ├── Contents.json │ │ └── setting1.png │ ├── setting3.imageset │ │ ├── Contents.json │ │ └── setting3.png │ ├── settings01副本.imageset │ │ ├── Contents.json │ │ └── settings01副本.png │ ├── 橙色.imageset │ │ ├── Contents.json │ │ └── 橙色.PNG │ ├── 蓝色.imageset │ │ ├── Contents.json │ │ └── 蓝色.png │ ├── 高雅紫.imageset │ │ ├── Contents.json │ │ └── purple.PNG │ └── 默认.imageset │ │ ├── Contents.json │ │ └── 默认.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Common.h ├── Common.m ├── Info.plist ├── ViewController.h ├── ViewController.m ├── click.wav ├── click1.wav ├── click2.wav ├── click3.wav ├── fmdb │ ├── FMDB.h │ ├── FMDatabase.h │ ├── FMDatabase.m │ ├── FMDatabaseAdditions.h │ ├── FMDatabaseAdditions.m │ ├── FMDatabasePool.h │ ├── FMDatabasePool.m │ ├── FMDatabaseQueue.h │ ├── FMDatabaseQueue.m │ ├── FMResultSet.h │ ├── FMResultSet.m │ └── Info.plist ├── historyTableViewCell.h ├── historyTableViewCell.m ├── historyTableViewCell.xib ├── main.m ├── savehistoryData.h ├── savehistoryData.m ├── setViewController.h ├── setViewController.m ├── setViewController.xib ├── themeCell.xib ├── themeViewController.h ├── themeViewController.m └── themeViewController.xib ├── Calculator1Tests ├── Calculator1Tests.m └── Info.plist ├── Calculator1UITests ├── Calculator1UITests.m └── Info.plist └── README.md /Calculator1.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Calculator1.xcodeproj/project.xcworkspace/xcuserdata/ruru.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1.xcodeproj/project.xcworkspace/xcuserdata/ruru.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Calculator1.xcodeproj/project.xcworkspace/xcuserdata/ruru.xcuserdatad/xcdebugger/Expressions.xcexplist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Calculator1.xcodeproj/xcuserdata/ruru.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 18 | 19 | 20 | 22 | 32 | 33 | 34 | 36 | 48 | 49 | 50 | 52 | 64 | 65 | 66 | 68 | 80 | 81 | 82 | 84 | 96 | 97 | 98 | 100 | 110 | 111 | 112 | 114 | 126 | 127 | 128 | 130 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /Calculator1.xcodeproj/xcuserdata/ruru.xcuserdatad/xcschemes/Calculator1.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Calculator1.xcodeproj/xcuserdata/ruru.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Calculator1.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DDEE59921CBCEDEA00FFFC46 16 | 17 | primary 18 | 19 | 20 | DDEE59AB1CBCEDEB00FFFC46 21 | 22 | primary 23 | 24 | 25 | DDEE59B61CBCEDEB00FFFC46 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Calculator1/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Calculator1/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 21 | return YES; 22 | } 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 27 | } 28 | 29 | - (void)applicationDidEnterBackground:(UIApplication *)application { 30 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 31 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 32 | } 33 | 34 | - (void)applicationWillEnterForeground:(UIApplication *)application { 35 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 36 | } 37 | 38 | - (void)applicationDidBecomeActive:(UIApplication *)application { 39 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 40 | } 41 | 42 | - (void)applicationWillTerminate:(UIApplication *)application { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/11.imageset/11.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/11.imageset/11.jpeg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "11.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/33.imageset/33.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/33.imageset/33.jpeg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/33.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "33.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/44.imageset/44.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/44.imageset/44.jpeg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/44.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "44.jpeg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "size" : "60x60", 25 | "idiom" : "iphone", 26 | "filename" : "图标.png", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "size" : "60x60", 31 | "idiom" : "iphone", 32 | "filename" : "icon副本.png", 33 | "scale" : "3x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/AppIcon.appiconset/icon副本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/AppIcon.appiconset/icon副本.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/AppIcon.appiconset/图标.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/AppIcon.appiconset/图标.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back-1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "back.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back-1.imageset/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back-1.imageset/back.jpg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "back.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back.imageset/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back.imageset/back.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_ocean.imageset/1358750368853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back_ocean.imageset/1358750368853.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_ocean.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1358750368853.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_red.imageset/1426583873861.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back_red.imageset/1426583873861.jpg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_red.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1426583873861.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sky_dark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "af42ed5ad1574e94b9b869613d6dc658.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sky_dark.imageset/af42ed5ad1574e94b9b869613d6dc658.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back_sky_dark.imageset/af42ed5ad1574e94b9b869613d6dc658.jpg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sky_yellow.imageset/141146361770.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back_sky_yellow.imageset/141146361770.jpg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sky_yellow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "141146361770.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sunshine.imageset/1411463611130.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/back_sunshine.imageset/1411463611130.jpg -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/back_sunshine.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1411463611130.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/next.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "next.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/next.imageset/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/next.imageset/next.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/ok.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ok.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/ok.imageset/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/ok.imageset/ok.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/ok11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ok.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/ok11.imageset/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/ok11.imageset/ok.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/set1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "set1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/set1.imageset/set1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/set1.imageset/set1.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/set2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "set2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/set2.imageset/set2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/set2.imageset/set2.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "setting.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting.imageset/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/setting.imageset/setting.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "setting1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting1.imageset/setting1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/setting1.imageset/setting1.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "setting3.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/setting3.imageset/setting3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/setting3.imageset/setting3.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/settings01副本.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "settings01副本.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/settings01副本.imageset/settings01副本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/settings01副本.imageset/settings01副本.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/橙色.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "橙色.PNG", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/橙色.imageset/橙色.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/橙色.imageset/橙色.PNG -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/蓝色.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "蓝色.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/蓝色.imageset/蓝色.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/蓝色.imageset/蓝色.png -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/高雅紫.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "purple.PNG", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/高雅紫.imageset/purple.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/高雅紫.imageset/purple.PNG -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/默认.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "默认.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Calculator1/Assets.xcassets/默认.imageset/默认.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/Assets.xcassets/默认.imageset/默认.png -------------------------------------------------------------------------------- /Calculator1/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Calculator1/Common.h: -------------------------------------------------------------------------------- 1 | // 2 | // Common.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/26. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "FMDatabase.h" 12 | #import "FMResultSet.h" 13 | 14 | @interface Common : NSObject 15 | 16 | 17 | +(void)configSet:(NSString *)key value:(id)value;//声明存数据函数 18 | +(id)configGet:(NSString *)key;//声明读取数据函数 19 | +(id)configGetClcikMusic:(NSString *)key; 20 | +(void)configMusicOnSet:(BOOL)on; 21 | +(BOOL)configMusicOnGet; 22 | +(id)configGetTheme:(NSString *)key; 23 | +(void)writeImage:(UIImage *)image toFileAtPath:(NSString *)aPath; 24 | 25 | 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Calculator1/Common.m: -------------------------------------------------------------------------------- 1 | // 2 | // Common.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/26. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "Common.h" 10 | 11 | 12 | @implementation Common 13 | //方法一 14 | +(void)configSet:(NSString *)key value:(id)value{ 15 | NSUserDefaults *saveData=[NSUserDefaults standardUserDefaults]; 16 | [saveData setObject:value forKey:key]; 17 | [saveData synchronize]; 18 | } 19 | 20 | +(id)configGet:(NSString *)key{ 21 | NSUserDefaults *readData=[NSUserDefaults standardUserDefaults]; 22 | return [readData objectForKey:key]; 23 | } 24 | +(id)configGetClcikMusic:(NSString *)key{ 25 | NSUserDefaults *readData=[NSUserDefaults standardUserDefaults]; 26 | return [readData arrayForKey:key]; 27 | } 28 | +(id)configGetTheme:(NSString *)key{ 29 | NSUserDefaults *readData=[NSUserDefaults standardUserDefaults]; 30 | return [readData dictionaryForKey:key]; 31 | } 32 | //方法二 33 | +(void)configMusicOnSet:(BOOL)on{ 34 | [Common configSet:@"key_music_on" value:[NSString stringWithFormat:@"%d",on]]; 35 | } 36 | +(BOOL)configMusicOnGet{ 37 | BOOL defaultValue = YES; 38 | if([self configGet:@"key_music_on"]){ 39 | return [[self configGet:@"key_music_on"] intValue]; 40 | }else{ 41 | [Common configSet:@"key_music_on" value:[NSString stringWithFormat:@"%d",defaultValue]]; 42 | return defaultValue; 43 | } 44 | } 45 | //把UIImage保存到文件的方法 46 | +(void)writeImage:(UIImage *)image toFileAtPath:(NSString *)aPath{ 47 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); 48 | NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:aPath]]; 49 | NSLog(@"filePath%@",filePath); 50 | NSData *imageData = UIImagePNGRepresentation(image); 51 | [imageData writeToFile:aPath atomically:YES]; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Calculator1/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | 备忘计算器 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | 27 | LSRequiresIPhoneOS 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UIStatusBarStyle 38 | UIStatusBarStyleBlackTranslucent 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | 43 | UIViewControllerBasedStatusBarAppearance 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Calculator1/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "Common.h" 11 | #import "FMDatabase.h" 12 | #import "FMResultSet.h" 13 | #import "FMDatabaseAdditions.h" 14 | #import "savehistoryData.h" 15 | 16 | @interface ViewController : UIViewController 17 | @property (weak, nonatomic) IBOutlet UIView *backView; 18 | @property (weak, nonatomic) IBOutlet UIImageView *backImageView; 19 | 20 | @property (weak, nonatomic) IBOutlet UILabel *mathLabel; 21 | 22 | - (IBAction)settingBtn:(id)sender; 23 | 24 | 25 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollerView; 26 | @property (strong, nonatomic) IBOutlet UIView *keyboardView; 27 | 28 | @property (weak, nonatomic) IBOutlet UIView *keyboardView2; 29 | @property (strong, nonatomic) IBOutlet UILabel *resultLabel; 30 | @property (weak, nonatomic) IBOutlet UIView *subKeyboardView; 31 | @property (weak, nonatomic) IBOutlet UIView *subKeyboardView2; 32 | @property (weak, nonatomic) IBOutlet UITableView *historyTableView; 33 | @property (weak, nonatomic) IBOutlet UIView *historyView; 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Calculator1/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // bug:1按下等号之后再按todo就不能正常运算了。例如按下"1+5=6+8" 8 | // 2按下todo后按数字再按等号显示不正常, 9 | 10 | #import "ViewController.h" 11 | #import 12 | #import "historyTableViewCell.h" 13 | #import "setViewController.h" 14 | 15 | #define RGB(color) [UIColor colorWithRed:(color>>16)/255.0 green:((color>>8)&0xff)/255.0 blue:(color&0xff)/255.0 alpha:1] 16 | #define RGBA(color,opacity) [UIColor colorWithRed:(color>>16)/255.0 green:((color>>8)&0xff)/255.0 blue:(color&0xff)/255.0 alpha:opacity] 17 | 18 | @interface ViewController () 19 | 20 | @end 21 | 22 | @implementation ViewController{ 23 | NSString * numberBefore; //前个数字 24 | NSString * numberCurrent; //当前数字 25 | NSString * actionType; //当前存储的加减乘除动作 + - * / 26 | double result; 27 | BOOL isActionTypeMove; //加减乘除已经做了移位 28 | BOOL isStatusEqual; //是否按了等号 29 | BOOL isStatusDEG; 30 | NSMutableArray *historyData; 31 | NSIndexPath *secletIndexPath; 32 | int musicOn; 33 | 34 | } 35 | - (void)viewDidLoad { 36 | [self.navigationController setNavigationBarHidden:YES];//隐藏导航栏 37 | historyData=[[NSMutableArray alloc]init]; 38 | [super viewDidLoad]; 39 | self.subKeyboardView.hidden=YES; 40 | self.subKeyboardView2.hidden=NO; 41 | isStatusDEG=YES; 42 | self.historyTableView.delegate=self; 43 | self.historyTableView.dataSource=self; 44 | [self clearDate]; 45 | numberCurrent=@"0"; 46 | [self performSelector:@selector(bindEvent) withObject:nil afterDelay:0.01]; 47 | 48 | CGRect historyFrame = self.historyView.frame; 49 | historyFrame.origin.x=0; 50 | self.historyView.frame = historyFrame; 51 | self.historyView.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.2]; 52 | [self readHistoryData]; 53 | 54 | 55 | CGRect keyboardNumberFrame = self.keyboardView.frame; 56 | keyboardNumberFrame.origin.x=self.view.frame.size.width; 57 | self.keyboardView.frame = keyboardNumberFrame; 58 | 59 | CGRect keyboardMathFrame = self.keyboardView2.frame; 60 | keyboardMathFrame.origin.x=self.view.frame.size.width*2; 61 | self.keyboardView2.frame = keyboardMathFrame; 62 | 63 | CGSize size = self.scrollerView.contentSize; 64 | size.width = self.keyboardView.frame.size.width*3; 65 | self.scrollerView.contentSize=size; 66 | 67 | CGPoint scrollContentOffset = self.scrollerView.contentOffset; 68 | scrollContentOffset.x= self.view.frame.size.width; 69 | self.scrollerView.contentOffset = scrollContentOffset; 70 | } 71 | 72 | -(void)viewWillAppear:(BOOL)animated{ 73 | musicOn=[[Common configGet:@"key_music_on"]intValue]; 74 | NSDictionary *themeDic=[Common configGetTheme:@"key_setting_theme"]; 75 | NSString *isStateDefine=[Common configGet:@"theme_Define_background"]; 76 | int DefineInt=[isStateDefine intValue]; 77 | if (DefineInt) { 78 | self.backView.hidden=NO; 79 | [self setDenfineBackground]; 80 | [self setBackgroundBeffect]; 81 | }else if ([[themeDic objectForKey:@"theme_background_color"] isKindOfClass:[NSArray class]]) { 82 | self.backView.hidden=YES; 83 | NSString *color = [[themeDic objectForKey:@"theme_background_color"] objectAtIndex:0 ]; 84 | long int colorInt =strtoul([color UTF8String],0,16);//字符串转成 85 | self.view.backgroundColor=RGB(colorInt); 86 | }else if([[themeDic objectForKey:@"theme_background_color"] isKindOfClass:[NSString class]]){ 87 | self.backView.hidden=NO; 88 | [self setImageBackground]; 89 | [self setBackgroundBeffect]; 90 | } 91 | [self SetButtonColor]; 92 | } 93 | -(void)setDenfineBackground{ 94 | NSString *fullPath=[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"backgroundImage.png"]; 95 | UIImage *saveDefineImage=[[UIImage alloc] initWithContentsOfFile:fullPath]; 96 | UIImageView * back = (UIImageView *)[self.backView subviews][0]; 97 | [back setImage:saveDefineImage]; 98 | } 99 | -(void)setImageBackground{ 100 | NSDictionary *themeDict=[Common configGetTheme:@"key_setting_theme"]; 101 | NSString *backgroundImage=[themeDict objectForKey:@"theme_background_color"]; 102 | UIImageView * back = (UIImageView *)[self.backView subviews][0]; 103 | [back setImage:[UIImage imageNamed:backgroundImage]]; 104 | } 105 | -(void)setBackgroundBeffect{ 106 | UIView *subviews = [self.backView viewWithTag:800];//使用viewWtihTag非常方便,可以通过父View的viewWtihTag获取到子View,但是前提是创建子View的时候要加tag,如: 107 | [subviews removeFromSuperview]; 108 | 109 | UIBlurEffect *beffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 110 | UIVisualEffectView *BeffectView = [[UIVisualEffectView alloc]initWithEffect:beffect]; 111 | BeffectView.frame = self.backView.bounds; 112 | BeffectView.tag=800; 113 | int bgBlurEffectSata=[[Common configGet:@"key_bg_lurEffect_on"]intValue]; 114 | if (bgBlurEffectSata) { 115 | [self.backView addSubview:BeffectView]; 116 | }else{ 117 | if ([BeffectView isKindOfClass:[self.backView class]]) { 118 | } 119 | } 120 | } 121 | -(void)SetButtonColor{ 122 | if (![Common configGetTheme:@"key_setting_theme"]) { 123 | return; 124 | } 125 | NSDictionary *themeDict=[Common configGetTheme:@"key_setting_theme"]; 126 | // NSLog(@"themeDict======%@",themeDict); 127 | NSString *BtnBgColor=[[themeDict objectForKey:@"button_background_color"] objectAtIndex:0 ]; 128 | long int BtnBgColorInt =strtoul([BtnBgColor UTF8String],0,16);//字符串转成 129 | NSString *BtnTitleColor=[[themeDict objectForKey:@"font-color"] objectAtIndex:0 ]; 130 | long int BtnTitleColorInt =strtoul([BtnTitleColor UTF8String],0,16);//字符串转成 131 | 132 | int tag; 133 | for (tag=10; tag<=57; tag++) { 134 | UIButton *button = (UIButton *)[self.keyboardView viewWithTag:tag]; 135 | UIButton *button1= (UIButton *)[self.keyboardView2 viewWithTag:tag]; 136 | UIButton *button2 = (UIButton *)[self.subKeyboardView viewWithTag:tag]; 137 | UIButton *button3 = (UIButton *)[self.subKeyboardView2 viewWithTag:tag]; 138 | 139 | [button setBackgroundColor:RGB(BtnBgColorInt)]; 140 | [button1 setBackgroundColor:RGB(BtnBgColorInt)]; 141 | [button2 setBackgroundColor:RGB(BtnBgColorInt)]; 142 | [button3 setBackgroundColor:RGB(BtnBgColorInt)]; 143 | [button setTitleColor:RGB(BtnTitleColorInt) forState:UIControlStateNormal]; 144 | [button1 setTitleColor:RGB(BtnTitleColorInt) forState:UIControlStateNormal]; 145 | [button2 setTitleColor:RGB(BtnTitleColorInt) forState:UIControlStateNormal]; 146 | [button3 setTitleColor:RGB(BtnTitleColorInt) forState:UIControlStateNormal]; 147 | } 148 | for (tag=20; tag<=22; tag++) { 149 | UIButton *button = (UIButton *)[self.keyboardView viewWithTag:tag]; 150 | long int colorInt =strtoul([[[themeDict objectForKey:@"specialButton_bg_color"] objectAtIndex:0 ] UTF8String],0,16);//字符串转成 151 | [button setBackgroundColor:RGB(colorInt)]; 152 | } 153 | for (tag=23; tag<=27; tag++) { 154 | UIButton *button = (UIButton *)[self.keyboardView viewWithTag:tag]; 155 | long int colorInt =strtoul([[[themeDict objectForKey:@"button_Key_color"] objectAtIndex:0 ] UTF8String],0,16);//字符串转成 156 | [button setBackgroundColor:RGB(colorInt)]; 157 | } 158 | } 159 | -(void)clearDate{ 160 | numberBefore=nil; 161 | numberCurrent=@"0"; 162 | actionType=nil; 163 | result=0; 164 | isActionTypeMove=NO; 165 | isStatusEqual=NO; 166 | self.resultLabel.text=@"0"; 167 | self.mathLabel.text=@""; 168 | } 169 | 170 | -(void)bindEvent{ 171 | NSMutableArray * arr = [NSMutableArray array]; 172 | [arr addObjectsFromArray:self.keyboardView.subviews]; 173 | [arr addObjectsFromArray:self.keyboardView2.subviews]; 174 | [arr addObjectsFromArray:self.subKeyboardView.subviews]; 175 | [arr addObjectsFromArray:self.subKeyboardView2.subviews]; 176 | [arr addObjectsFromArray:self.view.subviews]; 177 | for (UIButton *button in arr) { 178 | if ([button isKindOfClass:[UIButton class]]) { 179 | [button addTarget:self action:@selector(pressDownAction:) forControlEvents:UIControlEventTouchDown ]; 180 | [button addTarget:self action:@selector(pressUpAction:) forControlEvents:UIControlEventTouchUpInside]; 181 | [button addTarget:self action:@selector(pressClearAction:) forControlEvents:UIControlEventTouchUpOutside]; 182 | [button addTarget:self action:@selector(pressClearAction:) forControlEvents:UIControlEventTouchCancel];//按下button是退出app 183 | 184 | CGRect frame = button.frame; 185 | frame.size.width+=0.5;frame.size.height+=0.5; 186 | button.frame = frame; 187 | } 188 | } 189 | } 190 | -(void)pressDownAction:(UIButton *)button{ 191 | NSArray *array=[Common configGetClcikMusic:@"MusicKey"]; 192 | NSLog(@"array%@",array); 193 | NSString *clickMusicStr=[array objectAtIndex:0]; 194 | if (musicOn) { 195 | if ([clickMusicStr isEqualToString:@"Music1"]) { 196 | [self playSoundEffect:@"click.wav"]; 197 | }else if([clickMusicStr isEqualToString:@"Music2"]){ 198 | [self playSoundEffect:@"click1.wav"]; 199 | }else if([clickMusicStr isEqualToString:@"Music3"]){ 200 | [self playSoundEffect:@"click2.wav"]; 201 | }else if([clickMusicStr isEqualToString:@"Music4"]){ 202 | [self playSoundEffect:@"click3.wav"]; 203 | } 204 | } 205 | NSLog(@"readmusic%@",[Common configGet:@"key_music_on"]); 206 | button.transform = CGAffineTransformMakeScale(0.95, 0.95); 207 | button.alpha=0.6; 208 | } 209 | //取消按钮动作动画 210 | -(void)pressClearAction:(UIButton *)button{ 211 | button.transform = CGAffineTransformMakeScale(1, 1); 212 | button.alpha=1; 213 | } 214 | -(void)clearActionButton{ 215 | int tag; 216 | for (tag=23; tag<=26; tag++) { 217 | UIButton * button = (UIButton *)[self.view viewWithTag:tag]; 218 | [self pressClearAction:button]; 219 | } 220 | } 221 | //抬起按钮的逻辑 222 | -(void)pressUpAction:(UIButton *)button{ 223 | [self pressClearAction:button]; 224 | int buttonTag=(int)button.tag; 225 | switch (buttonTag) { 226 | case 10:[self numberGreate:0]; break; //0为实际参数 227 | case 11:[self numberGreate:1]; break; 228 | case 12:[self numberGreate:2]; break; 229 | case 13:[self numberGreate:3]; break; 230 | case 14:[self numberGreate:4]; break; 231 | case 15:[self numberGreate:5]; break; 232 | case 16:[self numberGreate:6]; break; 233 | case 17:[self numberGreate:7]; break; 234 | case 18:[self numberGreate:8]; break; 235 | case 19:[self numberGreate:9]; break; 236 | case 20:[self clearDate] ; break; 237 | case 21:[self actionInverse] ;break; 238 | case 22:[self actionPercent] ;break; 239 | case 23:[self actionTodo:button type:@"÷"] ;break; 240 | case 24:[self actionTodo:button type:@"×"] ;break; 241 | case 25:[self actionTodo:button type:@"-"] ;break; 242 | case 26:[self actionTodo:button type:@"+"] ;break; 243 | case 27:[self actionEqual] ;break; 244 | case 28:[self actionPoint] ;break; 245 | 246 | case 30:[self actionE]; break; //0为实际参数 247 | case 31:[self actionPi]; break; 248 | case 32:[self actionDEG]; break; 249 | case 33:[self actionChangeSubkeyboardView]; break; 250 | case 34:[self actionSinh]; break; 251 | case 35:[self actionConh]; break; 252 | case 36:[self actionTanh]; break; 253 | case 37:[self actionEPow]; break; 254 | case 38:[self actionSin]; break; 255 | case 39:[self actionCos]; break; 256 | case 40:[self actionTan] ; break; 257 | case 41:[self actionLn] ;break; 258 | case 42:[self actionSquareRoot] ;break; 259 | case 43:[self actionCubeRoot] ;break; 260 | case 44:[self actionTodo:button type:@"˟√y"] ;break; 261 | case 45:[self actionLog] ;break; 262 | case 46:[self actionSquare] ;break; 263 | case 47:[self actionCube] ;break; 264 | case 48:[self actionTodo:button type:@"y^x"] ;break; 265 | case 49:[self actionFactorials] ;break; 266 | 267 | case 50:[self actionArcsin] ;break; 268 | case 51:[self actionArccos] ;break; 269 | case 52:[self actionArctan] ;break; 270 | case 53:[self actionLog2] ;break; 271 | case 54:[self actionArcsinh] ;break; 272 | case 55:[self actionArcconh] ;break; 273 | case 56:[self actionArctanh] ;break; 274 | case 57:[self action2pow] ;break; 275 | 276 | default:break; 277 | } 278 | [self mathMode]; 279 | } 280 | #pragma mark=======keyboardView2(math) 281 | -(void)actionSquare{ 282 | if (numberCurrent!=0) { 283 | double value=[numberCurrent doubleValue]*[numberCurrent doubleValue]; 284 | numberCurrent=[self subString:value]; 285 | [self setNumberDisplay:numberCurrent]; 286 | } 287 | } 288 | -(void)actionCube{ 289 | if (numberCurrent!=0) { 290 | double value=[numberCurrent doubleValue]*[numberCurrent doubleValue]*[numberCurrent doubleValue]; 291 | numberCurrent=[self subString:value]; 292 | [self setNumberDisplay:numberCurrent]; 293 | } 294 | } 295 | -(void)actionFactorials{//阶乘 296 | double i; double fac=1; 297 | if ([numberCurrent doubleValue]==0||[numberCurrent doubleValue]==1) { 298 | numberCurrent=[NSString stringWithFormat:@"1"]; 299 | }else if(numberCurrent>0){ 300 | double j=[numberCurrent doubleValue]; 301 | NSLog(@"j=%lf",j); 302 | for (i=2; i<=j; i++) { 303 | fac=fac*i; 304 | } 305 | numberCurrent=[self subString:fac]; 306 | } 307 | [self setNumberDisplay:numberCurrent]; 308 | } 309 | -(void)actionSquareRoot{ 310 | if ([numberCurrent doubleValue]>=0) { 311 | double value=sqrt([numberCurrent doubleValue]); 312 | numberCurrent=[self subString:value]; 313 | 314 | } 315 | [self setNumberDisplay:numberCurrent]; 316 | } 317 | -(void)actionCubeRoot{ 318 | double value=pow([numberCurrent doubleValue], 1.0/3); 319 | numberCurrent=[self subString:value]; 320 | [self setNumberDisplay:numberCurrent]; 321 | } 322 | -(void)actionE{ 323 | numberCurrent=[NSString stringWithFormat:@"2.718281828459"]; 324 | [self setNumberDisplay:numberCurrent]; 325 | } 326 | -(void)actionPi{ 327 | numberCurrent=[NSString stringWithFormat:@"3.1415926535898"]; 328 | [self setNumberDisplay:numberCurrent]; 329 | 330 | } 331 | -(void)changeDeg{ 332 | if (!isStatusDEG) { 333 | double Value=[numberCurrent doubleValue]*(3.1415926535898/180); 334 | NSString *str=[self subString:Value]; 335 | numberCurrent=str; 336 | // isStatusDEG=YES; 337 | } 338 | } 339 | -(void)actionDEG{ 340 | isStatusDEG=!isStatusDEG; 341 | if (isStatusDEG) { 342 | UIButton *button = (UIButton *)[self.view viewWithTag:32]; 343 | [button setTitle:@"Deg" forState:UIControlStateNormal]; 344 | }else{ 345 | UIButton *button=(UIButton *)[self.view viewWithTag:32]; 346 | [button setTitle:@"Rad" forState:UIControlStateNormal]; 347 | } 348 | 349 | } 350 | -(void)actionSin{ 351 | [self changeDeg]; 352 | double value=sin([numberCurrent doubleValue]); 353 | numberCurrent=[self subString:value]; 354 | [self setNumberDisplay:numberCurrent]; 355 | } 356 | -(void)actionArcsin{ 357 | [self changeDeg]; 358 | double value=1/sin([numberCurrent doubleValue]); 359 | numberCurrent=[self subString:value]; 360 | [self setNumberDisplay:numberCurrent]; 361 | } 362 | -(void)actionCos{ 363 | [self changeDeg]; 364 | double value=cos([numberCurrent doubleValue]); 365 | numberCurrent=[self subString:value]; 366 | [self setNumberDisplay:numberCurrent]; 367 | } 368 | -(void)actionArccos{ 369 | [self changeDeg]; 370 | double value=1/cos([numberCurrent doubleValue]); 371 | numberCurrent=[self subString:value]; 372 | [self setNumberDisplay:numberCurrent]; 373 | } 374 | -(void)actionTan{ 375 | [self changeDeg]; 376 | double value=tan([numberCurrent doubleValue]); 377 | numberCurrent=[self subString:value]; 378 | [self setNumberDisplay:numberCurrent]; 379 | } 380 | -(void)actionArctan{ 381 | [self changeDeg]; 382 | double value=1/tan([numberCurrent doubleValue]); 383 | numberCurrent=[self subString:value]; 384 | [self setNumberDisplay:numberCurrent]; 385 | } 386 | -(void)actionSinh{ 387 | [self changeDeg]; 388 | double value=sinh([numberCurrent doubleValue]); 389 | numberCurrent=[self subString:value]; 390 | [self setNumberDisplay:numberCurrent]; 391 | } 392 | -(void)actionArcsinh{ 393 | [self changeDeg]; 394 | double value=1/sinh([numberCurrent doubleValue]); 395 | numberCurrent=[self subString:value]; 396 | [self setNumberDisplay:numberCurrent]; 397 | } 398 | -(void)actionConh{ 399 | [self changeDeg]; 400 | double value=cosh([numberCurrent doubleValue]); 401 | numberCurrent=[self subString:value]; 402 | [self setNumberDisplay:numberCurrent]; 403 | } 404 | -(void)actionArcconh{ 405 | [self changeDeg]; 406 | double value=1/cosh([numberCurrent doubleValue]); 407 | numberCurrent=[self subString:value]; 408 | [self setNumberDisplay:numberCurrent]; 409 | } 410 | 411 | -(void)actionTanh{ 412 | [self changeDeg]; 413 | double value=tanh([numberCurrent doubleValue]); 414 | numberCurrent=[self subString:value]; 415 | [self setNumberDisplay:numberCurrent]; 416 | } 417 | -(void)actionArctanh{ 418 | [self changeDeg]; 419 | double value=1/tanh([numberCurrent doubleValue]); 420 | numberCurrent=[self subString:value]; 421 | [self setNumberDisplay:numberCurrent]; 422 | } 423 | 424 | -(void)actionEPow{//e^x 425 | double e=2.718281828459; 426 | double value=pow(e, [numberCurrent doubleValue]); 427 | numberCurrent=[self subString:value]; 428 | [self setNumberDisplay:numberCurrent]; 429 | } 430 | -(void)action2pow{ 431 | double value=pow(2,[numberCurrent doubleValue]); 432 | numberCurrent=[self subString:value]; 433 | [self setNumberDisplay:numberCurrent]; 434 | } 435 | -(void)actionLog{ 436 | if ([numberCurrent doubleValue]>0) { 437 | double value=log10([numberCurrent doubleValue]); 438 | numberCurrent=[self subString:value]; 439 | } 440 | [self setNumberDisplay:numberCurrent]; 441 | } 442 | -(void)actionLn{ 443 | if ([numberCurrent doubleValue]>0) { 444 | double value=log([numberCurrent doubleValue]); 445 | numberCurrent=[self subString:value]; 446 | } 447 | [self setNumberDisplay:numberCurrent]; 448 | } 449 | -(void)actionLog2{ 450 | if ([numberCurrent doubleValue]>0) { 451 | double value=log2([numberCurrent doubleValue]); 452 | numberCurrent=[self subString:value]; 453 | } 454 | [self setNumberDisplay:numberCurrent]; 455 | } 456 | -(void)actionChangeSubkeyboardView{ 457 | self.subKeyboardView.hidden=!self.subKeyboardView.hidden; 458 | self.subKeyboardView2.hidden=!self.subKeyboardView2.hidden; 459 | } 460 | 461 | -(void)actionInverse{ //取反 462 | if ([numberCurrent doubleValue]) { 463 | if (!isStatusEqual) { 464 | double doubleValue=-[numberCurrent doubleValue]; 465 | numberCurrent=[self subString:doubleValue]; 466 | [self setNumberDisplay:numberCurrent]; 467 | }else{ 468 | double Value=-result; 469 | NSString *str=[self subString:Value]; 470 | [self setNumberDisplay:str]; 471 | result=Value; 472 | } 473 | } 474 | } 475 | -(void)actionPercent{ 476 | if ([numberCurrent doubleValue]) { 477 | if (!isStatusEqual) { 478 | double doubleValue=[numberCurrent doubleValue]/100; 479 | numberCurrent=[self subString:doubleValue]; 480 | [self setNumberDisplay:numberCurrent]; 481 | }else{ 482 | double Value=result/100; 483 | NSString *str=[self subString:Value]; 484 | [self setNumberDisplay:str]; 485 | result=Value; 486 | } 487 | } 488 | } 489 | -(void)actionPoint{ 490 | if ([self stringHasPoint:numberCurrent]) { 491 | return; 492 | }else{ 493 | numberCurrent=[NSString stringWithFormat:@"%@.",numberCurrent]; 494 | [self setNumberDisplay:numberCurrent]; 495 | } 496 | } 497 | -(BOOL)stringHasPoint:(NSString *)string{ 498 | NSRange rang=[string rangeOfString:@"."]; 499 | if (rang.length>0) { 500 | return YES; 501 | }else{ 502 | return NO; 503 | } 504 | } 505 | #pragma mark=======math Action 506 | -(void)numberGreate:(int)number{//number形式参数 507 | if (isStatusEqual) { 508 | [self clearDate]; 509 | } 510 | if (actionType&&!isActionTypeMove){ 511 | numberBefore=numberCurrent; 512 | numberCurrent=@"0"; 513 | isActionTypeMove=YES; 514 | } 515 | if ([numberCurrent isEqualToString:@"0"]) { 516 | numberCurrent=[NSString stringWithFormat:@"%d",number]; 517 | }else if([self stringHasPoint:numberCurrent]||[[numberCurrent substringWithRange:NSMakeRange(0,1)]isEqualToString:@"-"]) { 518 | if (numberCurrent.length>=10) { 519 | return; 520 | }else{ 521 | numberCurrent=[NSString stringWithFormat:@"%@%d",numberCurrent,number]; 522 | } 523 | }else if (numberCurrent.length>=9) { 524 | return; 525 | }else{ 526 | numberCurrent=[NSString stringWithFormat:@"%@%d",numberCurrent,number]; 527 | } 528 | [self setNumberDisplay:numberCurrent]; 529 | [self mathLabel]; 530 | } 531 | -(void)actionTodo:(UIButton *)button type:(NSString *)type{ 532 | isActionTypeMove=NO; 533 | if ([numberCurrent isEqualToString:@"0"]) { 534 | return; 535 | } 536 | if (numberBefore&&![numberCurrent isEqualToString:@""]&&actionType){ 537 | if (isStatusEqual) { 538 | numberCurrent=[self subString:result]; 539 | isStatusEqual=NO; 540 | }else{ 541 | [self calculationType]; 542 | numberCurrent=[self subString:result]; 543 | [self setNumberDisplay:numberCurrent]; 544 | NSLog(@"NU%@",numberCurrent); 545 | } 546 | } 547 | actionType=type; 548 | } 549 | 550 | -(void)mathMode{ 551 | 552 | if (numberCurrent&&!actionType) { 553 | self.mathLabel.text=[self setNumber:numberCurrent]; 554 | }else if(numberCurrent&&actionType&&!numberBefore){ 555 | self.mathLabel.text=[NSString stringWithFormat:@"%@ %@",[self setNumber:numberCurrent],actionType]; 556 | }else if(numberBefore&&![numberCurrent isEqualToString:@""]&&actionType&&!isStatusEqual){ 557 | if (isActionTypeMove) { 558 | self.mathLabel.text=[NSString stringWithFormat:@"%@ %@ %@",[self setNumber:numberBefore],actionType,[self setNumber:numberCurrent]]; 559 | }else{ 560 | self.mathLabel.text=[NSString stringWithFormat:@"%@ %@",[self setNumber:numberCurrent],actionType]; 561 | } 562 | }else if(numberCurrent&&actionType&&numberBefore){ 563 | if (isStatusEqual) { 564 | self.mathLabel.text=[NSString stringWithFormat:@"%@ %@ %@ =",[self setNumber:numberBefore],actionType,[self setNumber:numberCurrent]]; 565 | } 566 | } 567 | } 568 | -(void)actionEqual{ 569 | if (!numberBefore) { 570 | return; 571 | } 572 | if (!isStatusEqual) { 573 | [self calculationType]; 574 | }else{ 575 | numberBefore=[self subString:result]; 576 | [self calculationType]; 577 | } 578 | NSString *resultStr=[self subString:result]; 579 | [self setNumberDisplay:resultStr]; 580 | [savehistoryData historyAdd: [self time] beforeNum:[self setNumber:numberBefore] operationType:actionType CurrentNub:[self setNumber:numberCurrent] result:[self setNumber:resultStr]]; 581 | [self readHistoryData]; 582 | 583 | isStatusEqual=YES; 584 | } 585 | -(void)calculationType{ 586 | if ([actionType isEqualToString:@"+"]) { 587 | result=[numberBefore doubleValue]+[numberCurrent doubleValue]; 588 | }else if([actionType isEqualToString:@"-"]){ 589 | result=[numberBefore doubleValue]-[numberCurrent doubleValue]; 590 | }else if([actionType isEqualToString:@"×"]){ 591 | result=[numberBefore doubleValue]*[numberCurrent doubleValue]; 592 | }else if([actionType isEqualToString:@"÷"]){ 593 | result=[numberBefore doubleValue]/[numberCurrent doubleValue]; 594 | }else if([actionType isEqualToString:@"y^x"]){ 595 | result=pow([numberBefore doubleValue], [numberCurrent doubleValue]); 596 | }else if([actionType isEqualToString:@"˟√y"]){ 597 | result=pow([numberBefore doubleValue], 1/[numberCurrent doubleValue]); 598 | } 599 | } 600 | -(void)setNumberDisplay:(NSString *)numberDisplay{ 601 | self.resultLabel.text=[self setNumber:numberDisplay]; 602 | } 603 | -(NSString *)setNumber:(NSString *)number{ 604 | NSMutableString *strnumber=[[NSMutableString alloc]init]; 605 | strnumber=[number mutableCopy]; 606 | int length=(int)strnumber.length; 607 | int index; 608 | NSRange rang=[strnumber rangeOfString:@"."]; 609 | if (rang.length>0) { 610 | for ( int j=0; j<=length; j++) { 611 | NSString *Char=[strnumber substringWithRange:NSMakeRange(j, 1)]; 612 | if ([Char isEqualToString:@"."]) { 613 | index=j; 614 | break; 615 | } 616 | }if (33; i=i-3) {//找出小数点为位置i 618 | if ([[strnumber substringWithRange:NSMakeRange(i-4,1)]isEqualToString:@"-"]) { 619 | break; 620 | }else{ 621 | [strnumber insertString:@"," atIndex:i-3]; 622 | } 623 | } 624 | } 625 | } else if (33; i=i-3) { 627 | if ([[strnumber substringWithRange:NSMakeRange(i-4,1)]isEqualToString:@"-"]) { 628 | break; 629 | }else{ 630 | [strnumber insertString:@"," atIndex:i-3]; 631 | } 632 | } 633 | } 634 | else if(length>9){ 635 | if ([[strnumber substringWithRange:NSMakeRange(0, 1)]isEqualToString:@"-"]) { 636 | NSString *fisrtChar=[strnumber substringWithRange:NSMakeRange(1, 1)]; 637 | NSString *afterPointChar=[strnumber substringWithRange:NSMakeRange(2, 5)]; 638 | NSString *lengthStr=[NSString stringWithFormat:@"%lu",(unsigned long)strnumber.length]; 639 | strnumber=[[NSString stringWithFormat:@"-%@.%@e%@",fisrtChar,afterPointChar,lengthStr]mutableCopy]; 640 | }else{ 641 | NSString *fisrtChar=[strnumber substringWithRange:NSMakeRange(0, 1)]; 642 | NSString *afterPointChar=[strnumber substringWithRange:NSMakeRange(1, 5)]; 643 | NSString *lengthStr=[NSString stringWithFormat:@"%lu",(unsigned long)strnumber.length]; 644 | strnumber=[[NSString stringWithFormat:@"%@.%@e%@",fisrtChar,afterPointChar,lengthStr]mutableCopy]; 645 | } 646 | } 647 | number=[strnumber copy]; 648 | return number; 649 | } 650 | -(NSString*)subString:(double)value{ //截取字符串 651 | NSString *str=[NSString stringWithFormat:@"%lf",value]; 652 | int index=(int) str.length; 653 | int i; 654 | for (i=(int)str.length;i>0;i--) { 655 | // NSLog(@"i=%d str.length=%d",i,(int)str.length); 656 | NSString *lastChar=[str substringWithRange:NSMakeRange(i-1, 1)]; 657 | if (![lastChar isEqualToString:@"0"]) { 658 | index=i; 659 | if ([lastChar isEqualToString:@"."]) { 660 | index--; 661 | }break; 662 | } 663 | } 664 | NSString *subString=[str substringWithRange:NSMakeRange(0, index)]; 665 | return subString; 666 | } 667 | #pragma mark 音效实现函数 668 | 669 | -(void)playSoundEffect:(NSString *)name{ 670 | NSString *audioFile=[[NSBundle mainBundle] pathForResource:name ofType:nil]; 671 | NSURL *fileUrl=[NSURL fileURLWithPath:audioFile]; 672 | SystemSoundID soundID=0;//获得系统声音ID 673 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID); 674 | AudioServicesPlaySystemSound(soundID);//播放音效 675 | } 676 | #pragma mark ======historyView 677 | 678 | #pragma mark 读取历史记录 679 | -(void)readHistoryData{ 680 | historyData=[savehistoryData seachHistoryData]; 681 | [self.historyTableView reloadData]; 682 | } 683 | -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ 684 | return 1; 685 | } 686 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 687 | return historyData.count; 688 | } 689 | -(UIViewController *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{ 690 | NSDictionary *cellInfo=historyData[indexPath.row]; 691 | return [[historyTableViewCell alloc]initWithData:cellInfo tableView:tableView]; 692 | } 693 | -(NSString *)time{ 694 | NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0]; 695 | NSTimeInterval a= [dat timeIntervalSince1970]; 696 | NSString *timeString = [NSString stringWithFormat:@"%ld",(long)a]; 697 | int currentTime=(int)a; 698 | NSLog(@"time%d",currentTime); 699 | return timeString; 700 | } 701 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 702 | secletIndexPath = indexPath; 703 | UIActionSheet *mysheet=[[UIActionSheet alloc]initWithTitle:nil delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"清空所有",@"删除",@"使用结果",nil]; 704 | [mysheet showInView:self.view]; 705 | } 706 | -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ 707 | switch (buttonIndex) { 708 | case 0: 709 | [savehistoryData deleteAllHistory]; 710 | [self readHistoryData]; 711 | break; 712 | case 1: 713 | [savehistoryData deleteSelectHistory:historyData[secletIndexPath.row][@"ID"]]; 714 | [self readHistoryData]; 715 | break; 716 | case 2: 717 | [self clearDate]; 718 | numberCurrent = [historyData[secletIndexPath.row][@"ResultStr"] stringByReplacingOccurrencesOfString:@"," withString:@""]; 719 | [self setNumberDisplay:numberCurrent]; 720 | 721 | CGPoint scrollerViewOffset = self.scrollerView.contentOffset; 722 | scrollerViewOffset.x = self.view.frame.size.width; 723 | [self.scrollerView setContentOffset:scrollerViewOffset animated:YES]; 724 | break; 725 | default:break; 726 | } 727 | } 728 | - (IBAction)settingBtn:(id)sender { 729 | setViewController *page=[[setViewController alloc]init]; 730 | [self.navigationController pushViewController:page animated:YES]; 731 | } 732 | @end 733 | -------------------------------------------------------------------------------- /Calculator1/click.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/click.wav -------------------------------------------------------------------------------- /Calculator1/click1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/click1.wav -------------------------------------------------------------------------------- /Calculator1/click2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/click2.wav -------------------------------------------------------------------------------- /Calculator1/click3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruruwei/Calculator/d0d5e84a925e473c90d4abf1a8b884bff0e8d440/Calculator1/click3.wav -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDB.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | FOUNDATION_EXPORT double FMDBVersionNumber; 4 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[]; 5 | 6 | #import "FMDatabase.h" 7 | #import "FMResultSet.h" 8 | #import "FMDatabaseAdditions.h" 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabasePool.h" 11 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | 12 | 13 | /** Category of additions for `` class. 14 | 15 | ### See also 16 | 17 | - `` 18 | */ 19 | 20 | @interface FMDatabase (FMDatabaseAdditions) 21 | 22 | ///---------------------------------------- 23 | /// @name Return results of SQL to variable 24 | ///---------------------------------------- 25 | 26 | /** Return `int` value for query 27 | 28 | @param query The SQL query to be performed. 29 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 30 | 31 | @return `int` value. 32 | 33 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 34 | */ 35 | 36 | - (int)intForQuery:(NSString*)query, ...; 37 | 38 | /** Return `long` value for query 39 | 40 | @param query The SQL query to be performed. 41 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 42 | 43 | @return `long` value. 44 | 45 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 46 | */ 47 | 48 | - (long)longForQuery:(NSString*)query, ...; 49 | 50 | /** Return `BOOL` value for query 51 | 52 | @param query The SQL query to be performed. 53 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 54 | 55 | @return `BOOL` value. 56 | 57 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 58 | */ 59 | 60 | - (BOOL)boolForQuery:(NSString*)query, ...; 61 | 62 | /** Return `double` value for query 63 | 64 | @param query The SQL query to be performed. 65 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 66 | 67 | @return `double` value. 68 | 69 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 70 | */ 71 | 72 | - (double)doubleForQuery:(NSString*)query, ...; 73 | 74 | /** Return `NSString` value for query 75 | 76 | @param query The SQL query to be performed. 77 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 78 | 79 | @return `NSString` value. 80 | 81 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 82 | */ 83 | 84 | - (NSString*)stringForQuery:(NSString*)query, ...; 85 | 86 | /** Return `NSData` value for query 87 | 88 | @param query The SQL query to be performed. 89 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 90 | 91 | @return `NSData` value. 92 | 93 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 94 | */ 95 | 96 | - (NSData*)dataForQuery:(NSString*)query, ...; 97 | 98 | /** Return `NSDate` value for query 99 | 100 | @param query The SQL query to be performed. 101 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 102 | 103 | @return `NSDate` value. 104 | 105 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 106 | */ 107 | 108 | - (NSDate*)dateForQuery:(NSString*)query, ...; 109 | 110 | 111 | // Notice that there's no dataNoCopyForQuery:. 112 | // That would be a bad idea, because we close out the result set, and then what 113 | // happens to the data that we just didn't copy? Who knows, not I. 114 | 115 | 116 | ///-------------------------------- 117 | /// @name Schema related operations 118 | ///-------------------------------- 119 | 120 | /** Does table exist in database? 121 | 122 | @param tableName The name of the table being looked for. 123 | 124 | @return `YES` if table found; `NO` if not found. 125 | */ 126 | 127 | - (BOOL)tableExists:(NSString*)tableName; 128 | 129 | /** The schema of the database. 130 | 131 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 132 | 133 | - `type` - The type of entity (e.g. table, index, view, or trigger) 134 | - `name` - The name of the object 135 | - `tbl_name` - The name of the table to which the object references 136 | - `rootpage` - The page number of the root b-tree page for tables and indices 137 | - `sql` - The SQL that created the entity 138 | 139 | @return `FMResultSet` of schema; `nil` on error. 140 | 141 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 142 | */ 143 | 144 | - (FMResultSet*)getSchema; 145 | 146 | /** The schema of the database. 147 | 148 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 149 | 150 | PRAGMA table_info('employees') 151 | 152 | This will report: 153 | 154 | - `cid` - The column ID number 155 | - `name` - The name of the column 156 | - `type` - The data type specified for the column 157 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 158 | - `dflt_value` - The default value for the column 159 | - `pk` - Whether the field is part of the primary key of the table 160 | 161 | @param tableName The name of the table for whom the schema will be returned. 162 | 163 | @return `FMResultSet` of schema; `nil` on error. 164 | 165 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 166 | */ 167 | 168 | - (FMResultSet*)getTableSchema:(NSString*)tableName; 169 | 170 | /** Test to see if particular column exists for particular table in database 171 | 172 | @param columnName The name of the column. 173 | 174 | @param tableName The name of the table. 175 | 176 | @return `YES` if column exists in table in question; `NO` otherwise. 177 | */ 178 | 179 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 180 | 181 | /** Test to see if particular column exists for particular table in database 182 | 183 | @param columnName The name of the column. 184 | 185 | @param tableName The name of the table. 186 | 187 | @return `YES` if column exists in table in question; `NO` otherwise. 188 | 189 | @see columnExists:inTableWithName: 190 | 191 | @warning Deprecated - use `` instead. 192 | */ 193 | 194 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); 195 | 196 | 197 | /** Validate SQL statement 198 | 199 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 200 | 201 | @param sql The SQL statement being validated. 202 | 203 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. 204 | 205 | @return `YES` if validation succeeded without incident; `NO` otherwise. 206 | 207 | */ 208 | 209 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; 210 | 211 | 212 | ///----------------------------------- 213 | /// @name Application identifier tasks 214 | ///----------------------------------- 215 | 216 | /** Retrieve application ID 217 | 218 | @return The `uint32_t` numeric value of the application ID. 219 | 220 | @see setApplicationID: 221 | */ 222 | 223 | - (uint32_t)applicationID; 224 | 225 | /** Set the application ID 226 | 227 | @param appID The `uint32_t` numeric value of the application ID. 228 | 229 | @see applicationID 230 | */ 231 | 232 | - (void)setApplicationID:(uint32_t)appID; 233 | 234 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 235 | /** Retrieve application ID string 236 | 237 | @return The `NSString` value of the application ID. 238 | 239 | @see setApplicationIDString: 240 | */ 241 | 242 | 243 | - (NSString*)applicationIDString; 244 | 245 | /** Set the application ID string 246 | 247 | @param string The `NSString` value of the application ID. 248 | 249 | @see applicationIDString 250 | */ 251 | 252 | - (void)setApplicationIDString:(NSString*)string; 253 | 254 | #endif 255 | 256 | ///----------------------------------- 257 | /// @name user version identifier tasks 258 | ///----------------------------------- 259 | 260 | /** Retrieve user version 261 | 262 | @return The `uint32_t` numeric value of the user version. 263 | 264 | @see setUserVersion: 265 | */ 266 | 267 | - (uint32_t)userVersion; 268 | 269 | /** Set the user-version 270 | 271 | @param version The `uint32_t` numeric value of the user version. 272 | 273 | @see userVersion 274 | */ 275 | 276 | - (void)setUserVersion:(uint32_t)version; 277 | 278 | @end 279 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabaseAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import "FMDatabase.h" 10 | #import "FMDatabaseAdditions.h" 11 | #import "TargetConditionals.h" 12 | 13 | #if FMDB_SQLITE_STANDALONE 14 | #import 15 | #else 16 | #import 17 | #endif 18 | 19 | @interface FMDatabase (PrivateStuff) 20 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; 21 | @end 22 | 23 | @implementation FMDatabase (FMDatabaseAdditions) 24 | 25 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ 26 | va_list args; \ 27 | va_start(args, query); \ 28 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ 29 | va_end(args); \ 30 | if (![resultSet next]) { return (type)0; } \ 31 | type ret = [resultSet sel:0]; \ 32 | [resultSet close]; \ 33 | [resultSet setParentDB:nil]; \ 34 | return ret; 35 | 36 | 37 | - (NSString*)stringForQuery:(NSString*)query, ... { 38 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); 39 | } 40 | 41 | - (int)intForQuery:(NSString*)query, ... { 42 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); 43 | } 44 | 45 | - (long)longForQuery:(NSString*)query, ... { 46 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); 47 | } 48 | 49 | - (BOOL)boolForQuery:(NSString*)query, ... { 50 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); 51 | } 52 | 53 | - (double)doubleForQuery:(NSString*)query, ... { 54 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); 55 | } 56 | 57 | - (NSData*)dataForQuery:(NSString*)query, ... { 58 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); 59 | } 60 | 61 | - (NSDate*)dateForQuery:(NSString*)query, ... { 62 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); 63 | } 64 | 65 | 66 | - (BOOL)tableExists:(NSString*)tableName { 67 | 68 | tableName = [tableName lowercaseString]; 69 | 70 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; 71 | 72 | //if at least one next exists, table exists 73 | BOOL returnBool = [rs next]; 74 | 75 | //close and free object 76 | [rs close]; 77 | 78 | return returnBool; 79 | } 80 | 81 | /* 82 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 83 | check if table exist in database (patch from OZLB) 84 | */ 85 | - (FMResultSet*)getSchema { 86 | 87 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 88 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; 89 | 90 | return rs; 91 | } 92 | 93 | /* 94 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 95 | */ 96 | - (FMResultSet*)getTableSchema:(NSString*)tableName { 97 | 98 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 99 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; 100 | 101 | return rs; 102 | } 103 | 104 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { 105 | 106 | BOOL returnBool = NO; 107 | 108 | tableName = [tableName lowercaseString]; 109 | columnName = [columnName lowercaseString]; 110 | 111 | FMResultSet *rs = [self getTableSchema:tableName]; 112 | 113 | //check if column is present in table schema 114 | while ([rs next]) { 115 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { 116 | returnBool = YES; 117 | break; 118 | } 119 | } 120 | 121 | //If this is not done FMDatabase instance stays out of pool 122 | [rs close]; 123 | 124 | return returnBool; 125 | } 126 | 127 | 128 | 129 | - (uint32_t)applicationID { 130 | #if SQLITE_VERSION_NUMBER >= 3007017 131 | uint32_t r = 0; 132 | 133 | FMResultSet *rs = [self executeQuery:@"pragma application_id"]; 134 | 135 | if ([rs next]) { 136 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 137 | } 138 | 139 | [rs close]; 140 | 141 | return r; 142 | #else 143 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); 144 | if (self.logsErrors) NSLog(@"%@", errorMessage); 145 | return 0; 146 | #endif 147 | } 148 | 149 | - (void)setApplicationID:(uint32_t)appID { 150 | #if SQLITE_VERSION_NUMBER >= 3007017 151 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; 152 | FMResultSet *rs = [self executeQuery:query]; 153 | [rs next]; 154 | [rs close]; 155 | #else 156 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); 157 | if (self.logsErrors) NSLog(@"%@", errorMessage); 158 | #endif 159 | } 160 | 161 | 162 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 163 | 164 | - (NSString*)applicationIDString { 165 | #if SQLITE_VERSION_NUMBER >= 3007017 166 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); 167 | 168 | assert([s length] == 6); 169 | 170 | s = [s substringWithRange:NSMakeRange(1, 4)]; 171 | 172 | 173 | return s; 174 | #else 175 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); 176 | if (self.logsErrors) NSLog(@"%@", errorMessage); 177 | return nil; 178 | #endif 179 | } 180 | 181 | - (void)setApplicationIDString:(NSString*)s { 182 | #if SQLITE_VERSION_NUMBER >= 3007017 183 | if ([s length] != 4) { 184 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); 185 | } 186 | 187 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; 188 | #else 189 | NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); 190 | if (self.logsErrors) NSLog(@"%@", errorMessage); 191 | #endif 192 | } 193 | 194 | #endif 195 | 196 | - (uint32_t)userVersion { 197 | uint32_t r = 0; 198 | 199 | FMResultSet *rs = [self executeQuery:@"pragma user_version"]; 200 | 201 | if ([rs next]) { 202 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 203 | } 204 | 205 | [rs close]; 206 | return r; 207 | } 208 | 209 | - (void)setUserVersion:(uint32_t)version { 210 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; 211 | FMResultSet *rs = [self executeQuery:query]; 212 | [rs next]; 213 | [rs close]; 214 | } 215 | 216 | #pragma clang diagnostic push 217 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 218 | 219 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { 220 | return [self columnExists:columnName inTableWithName:tableName]; 221 | } 222 | 223 | #pragma clang diagnostic pop 224 | 225 | 226 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 227 | sqlite3_stmt *pStmt = NULL; 228 | BOOL validationSucceeded = YES; 229 | 230 | int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); 231 | if (rc != SQLITE_OK) { 232 | validationSucceeded = NO; 233 | if (error) { 234 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 235 | code:[self lastErrorCode] 236 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 237 | forKey:NSLocalizedDescriptionKey]]; 238 | } 239 | } 240 | 241 | sqlite3_finalize(pStmt); 242 | 243 | return validationSucceeded; 244 | } 245 | 246 | @end 247 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FMDatabase; 12 | 13 | /** Pool of `` objects. 14 | 15 | ### See also 16 | 17 | - `` 18 | - `` 19 | 20 | @warning Before using `FMDatabasePool`, please consider using `` instead. 21 | 22 | If you really really really know what you're doing and `FMDatabasePool` is what 23 | you really really need (ie, you're using a read only database), OK you can use 24 | it. But just be careful not to deadlock! 25 | 26 | For an example on deadlocking, search for: 27 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` 28 | in the main.m file. 29 | */ 30 | 31 | @interface FMDatabasePool : NSObject { 32 | NSString *_path; 33 | 34 | dispatch_queue_t _lockQueue; 35 | 36 | NSMutableArray *_databaseInPool; 37 | NSMutableArray *_databaseOutPool; 38 | 39 | __unsafe_unretained id _delegate; 40 | 41 | NSUInteger _maximumNumberOfDatabasesToCreate; 42 | int _openFlags; 43 | NSString *_vfsName; 44 | } 45 | 46 | /** Database path */ 47 | 48 | @property (atomic, retain) NSString *path; 49 | 50 | /** Delegate object */ 51 | 52 | @property (atomic, assign) id delegate; 53 | 54 | /** Maximum number of databases to create */ 55 | 56 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 57 | 58 | /** Open flags */ 59 | 60 | @property (atomic, readonly) int openFlags; 61 | 62 | /** Custom virtual file system name */ 63 | 64 | @property (atomic, copy) NSString *vfsName; 65 | 66 | 67 | ///--------------------- 68 | /// @name Initialization 69 | ///--------------------- 70 | 71 | /** Create pool using path. 72 | 73 | @param aPath The file path of the database. 74 | 75 | @return The `FMDatabasePool` object. `nil` on error. 76 | */ 77 | 78 | + (instancetype)databasePoolWithPath:(NSString*)aPath; 79 | 80 | /** Create pool using path and specified flags 81 | 82 | @param aPath The file path of the database. 83 | @param openFlags Flags passed to the openWithFlags method of the database 84 | 85 | @return The `FMDatabasePool` object. `nil` on error. 86 | */ 87 | 88 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; 89 | 90 | /** Create pool using path. 91 | 92 | @param aPath The file path of the database. 93 | 94 | @return The `FMDatabasePool` object. `nil` on error. 95 | */ 96 | 97 | - (instancetype)initWithPath:(NSString*)aPath; 98 | 99 | /** Create pool using path and specified flags. 100 | 101 | @param aPath The file path of the database. 102 | @param openFlags Flags passed to the openWithFlags method of the database 103 | 104 | @return The `FMDatabasePool` object. `nil` on error. 105 | */ 106 | 107 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 108 | 109 | /** Create pool using path and specified flags. 110 | 111 | @param aPath The file path of the database. 112 | @param openFlags Flags passed to the openWithFlags method of the database 113 | @param vfsName The name of a custom virtual file system 114 | 115 | @return The `FMDatabasePool` object. `nil` on error. 116 | */ 117 | 118 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName; 119 | 120 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 121 | 122 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 123 | 124 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 125 | */ 126 | 127 | + (Class)databaseClass; 128 | 129 | ///------------------------------------------------ 130 | /// @name Keeping track of checked in/out databases 131 | ///------------------------------------------------ 132 | 133 | /** Number of checked-in databases in pool 134 | 135 | @returns Number of databases 136 | */ 137 | 138 | - (NSUInteger)countOfCheckedInDatabases; 139 | 140 | /** Number of checked-out databases in pool 141 | 142 | @returns Number of databases 143 | */ 144 | 145 | - (NSUInteger)countOfCheckedOutDatabases; 146 | 147 | /** Total number of databases in pool 148 | 149 | @returns Number of databases 150 | */ 151 | 152 | - (NSUInteger)countOfOpenDatabases; 153 | 154 | /** Release all databases in pool */ 155 | 156 | - (void)releaseAllDatabases; 157 | 158 | ///------------------------------------------ 159 | /// @name Perform database operations in pool 160 | ///------------------------------------------ 161 | 162 | /** Synchronously perform database operations in pool. 163 | 164 | @param block The code to be run on the `FMDatabasePool` pool. 165 | */ 166 | 167 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 168 | 169 | /** Synchronously perform database operations in pool using transaction. 170 | 171 | @param block The code to be run on the `FMDatabasePool` pool. 172 | */ 173 | 174 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 175 | 176 | /** Synchronously perform database operations in pool using deferred transaction. 177 | 178 | @param block The code to be run on the `FMDatabasePool` pool. 179 | */ 180 | 181 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 182 | 183 | /** Synchronously perform database operations in pool using save point. 184 | 185 | @param block The code to be run on the `FMDatabasePool` pool. 186 | 187 | @return `NSError` object if error; `nil` if successful. 188 | 189 | @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. 190 | */ 191 | 192 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 193 | 194 | @end 195 | 196 | 197 | /** FMDatabasePool delegate category 198 | 199 | This is a category that defines the protocol for the FMDatabasePool delegate 200 | */ 201 | 202 | @interface NSObject (FMDatabasePoolDelegate) 203 | 204 | /** Asks the delegate whether database should be added to the pool. 205 | 206 | @param pool The `FMDatabasePool` object. 207 | @param database The `FMDatabase` object. 208 | 209 | @return `YES` if it should add database to pool; `NO` if not. 210 | 211 | */ 212 | 213 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 214 | 215 | /** Tells the delegate that database was added to the pool. 216 | 217 | @param pool The `FMDatabasePool` object. 218 | @param database The `FMDatabase` object. 219 | 220 | */ 221 | 222 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 223 | 224 | @end 225 | 226 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabasePool.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #if FMDB_SQLITE_STANDALONE 10 | #import 11 | #else 12 | #import 13 | #endif 14 | 15 | #import "FMDatabasePool.h" 16 | #import "FMDatabase.h" 17 | 18 | @interface FMDatabasePool() 19 | 20 | - (void)pushDatabaseBackInPool:(FMDatabase*)db; 21 | - (FMDatabase*)db; 22 | 23 | @end 24 | 25 | 26 | @implementation FMDatabasePool 27 | @synthesize path=_path; 28 | @synthesize delegate=_delegate; 29 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; 30 | @synthesize openFlags=_openFlags; 31 | 32 | 33 | + (instancetype)databasePoolWithPath:(NSString*)aPath { 34 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); 35 | } 36 | 37 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { 38 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); 39 | } 40 | 41 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 42 | 43 | self = [super init]; 44 | 45 | if (self != nil) { 46 | _path = [aPath copy]; 47 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 48 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]); 49 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); 50 | _openFlags = openFlags; 51 | _vfsName = [vfsName copy]; 52 | } 53 | 54 | return self; 55 | } 56 | 57 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 58 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 59 | } 60 | 61 | - (instancetype)initWithPath:(NSString*)aPath 62 | { 63 | // default flags for sqlite3_open 64 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 65 | } 66 | 67 | - (instancetype)init { 68 | return [self initWithPath:nil]; 69 | } 70 | 71 | + (Class)databaseClass { 72 | return [FMDatabase class]; 73 | } 74 | 75 | - (void)dealloc { 76 | 77 | _delegate = 0x00; 78 | FMDBRelease(_path); 79 | FMDBRelease(_databaseInPool); 80 | FMDBRelease(_databaseOutPool); 81 | 82 | if (_lockQueue) { 83 | FMDBDispatchQueueRelease(_lockQueue); 84 | _lockQueue = 0x00; 85 | } 86 | #if ! __has_feature(objc_arc) 87 | [super dealloc]; 88 | #endif 89 | } 90 | 91 | 92 | - (void)executeLocked:(void (^)(void))aBlock { 93 | dispatch_sync(_lockQueue, aBlock); 94 | } 95 | 96 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 97 | 98 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 99 | return; 100 | } 101 | 102 | [self executeLocked:^() { 103 | 104 | if ([self->_databaseInPool containsObject:db]) { 105 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 106 | } 107 | 108 | [self->_databaseInPool addObject:db]; 109 | [self->_databaseOutPool removeObject:db]; 110 | 111 | }]; 112 | } 113 | 114 | - (FMDatabase*)db { 115 | 116 | __block FMDatabase *db; 117 | 118 | 119 | [self executeLocked:^() { 120 | db = [self->_databaseInPool lastObject]; 121 | 122 | BOOL shouldNotifyDelegate = NO; 123 | 124 | if (db) { 125 | [self->_databaseOutPool addObject:db]; 126 | [self->_databaseInPool removeLastObject]; 127 | } 128 | else { 129 | 130 | if (self->_maximumNumberOfDatabasesToCreate) { 131 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 132 | 133 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 134 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 135 | return; 136 | } 137 | } 138 | 139 | db = [[[self class] databaseClass] databaseWithPath:self->_path]; 140 | shouldNotifyDelegate = YES; 141 | } 142 | 143 | //This ensures that the db is opened before returning 144 | #if SQLITE_VERSION_NUMBER >= 3005000 145 | BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName]; 146 | #else 147 | BOOL success = [db open]; 148 | #endif 149 | if (success) { 150 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 151 | [db close]; 152 | db = 0x00; 153 | } 154 | else { 155 | //It should not get added in the pool twice if lastObject was found 156 | if (![self->_databaseOutPool containsObject:db]) { 157 | [self->_databaseOutPool addObject:db]; 158 | 159 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 160 | [self->_delegate databasePool:self didAddDatabase:db]; 161 | } 162 | } 163 | } 164 | } 165 | else { 166 | NSLog(@"Could not open up the database at path %@", self->_path); 167 | db = 0x00; 168 | } 169 | }]; 170 | 171 | return db; 172 | } 173 | 174 | - (NSUInteger)countOfCheckedInDatabases { 175 | 176 | __block NSUInteger count; 177 | 178 | [self executeLocked:^() { 179 | count = [self->_databaseInPool count]; 180 | }]; 181 | 182 | return count; 183 | } 184 | 185 | - (NSUInteger)countOfCheckedOutDatabases { 186 | 187 | __block NSUInteger count; 188 | 189 | [self executeLocked:^() { 190 | count = [self->_databaseOutPool count]; 191 | }]; 192 | 193 | return count; 194 | } 195 | 196 | - (NSUInteger)countOfOpenDatabases { 197 | __block NSUInteger count; 198 | 199 | [self executeLocked:^() { 200 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 201 | }]; 202 | 203 | return count; 204 | } 205 | 206 | - (void)releaseAllDatabases { 207 | [self executeLocked:^() { 208 | [self->_databaseOutPool removeAllObjects]; 209 | [self->_databaseInPool removeAllObjects]; 210 | }]; 211 | } 212 | 213 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 214 | 215 | FMDatabase *db = [self db]; 216 | 217 | block(db); 218 | 219 | [self pushDatabaseBackInPool:db]; 220 | } 221 | 222 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 223 | 224 | BOOL shouldRollback = NO; 225 | 226 | FMDatabase *db = [self db]; 227 | 228 | if (useDeferred) { 229 | [db beginDeferredTransaction]; 230 | } 231 | else { 232 | [db beginTransaction]; 233 | } 234 | 235 | 236 | block(db, &shouldRollback); 237 | 238 | if (shouldRollback) { 239 | [db rollback]; 240 | } 241 | else { 242 | [db commit]; 243 | } 244 | 245 | [self pushDatabaseBackInPool:db]; 246 | } 247 | 248 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 249 | [self beginTransaction:YES withBlock:block]; 250 | } 251 | 252 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 253 | [self beginTransaction:NO withBlock:block]; 254 | } 255 | 256 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 257 | #if SQLITE_VERSION_NUMBER >= 3007000 258 | static unsigned long savePointIdx = 0; 259 | 260 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 261 | 262 | BOOL shouldRollback = NO; 263 | 264 | FMDatabase *db = [self db]; 265 | 266 | NSError *err = 0x00; 267 | 268 | if (![db startSavePointWithName:name error:&err]) { 269 | [self pushDatabaseBackInPool:db]; 270 | return err; 271 | } 272 | 273 | block(db, &shouldRollback); 274 | 275 | if (shouldRollback) { 276 | // We need to rollback and release this savepoint to remove it 277 | [db rollbackToSavePointWithName:name error:&err]; 278 | } 279 | [db releaseSavePointWithName:name error:&err]; 280 | 281 | [self pushDatabaseBackInPool:db]; 282 | 283 | return err; 284 | #else 285 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 286 | if (self.logsErrors) NSLog(@"%@", errorMessage); 287 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 288 | #endif 289 | } 290 | 291 | @end 292 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FMDatabase; 12 | 13 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. 14 | 15 | Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. 16 | 17 | Instead, use `FMDatabaseQueue`. Here's how to use it: 18 | 19 | First, make your queue. 20 | 21 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 22 | 23 | Then use it like so: 24 | 25 | [queue inDatabase:^(FMDatabase *db) { 26 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 27 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 29 | 30 | FMResultSet *rs = [db executeQuery:@"select * from foo"]; 31 | while ([rs next]) { 32 | //… 33 | } 34 | }]; 35 | 36 | An easy way to wrap things up in a transaction can be done like this: 37 | 38 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 39 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 40 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 42 | 43 | if (whoopsSomethingWrongHappened) { 44 | *rollback = YES; 45 | return; 46 | } 47 | // etc… 48 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; 49 | }]; 50 | 51 | `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. 52 | 53 | ### See also 54 | 55 | - `` 56 | 57 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. 58 | 59 | @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. 60 | 61 | */ 62 | 63 | @interface FMDatabaseQueue : NSObject { 64 | NSString *_path; 65 | dispatch_queue_t _queue; 66 | FMDatabase *_db; 67 | int _openFlags; 68 | NSString *_vfsName; 69 | } 70 | 71 | /** Path of database */ 72 | 73 | @property (atomic, retain) NSString *path; 74 | 75 | /** Open flags */ 76 | 77 | @property (atomic, readonly) int openFlags; 78 | 79 | /** Custom virtual file system name */ 80 | 81 | @property (atomic, copy) NSString *vfsName; 82 | 83 | ///---------------------------------------------------- 84 | /// @name Initialization, opening, and closing of queue 85 | ///---------------------------------------------------- 86 | 87 | /** Create queue using path. 88 | 89 | @param aPath The file path of the database. 90 | 91 | @return The `FMDatabaseQueue` object. `nil` on error. 92 | */ 93 | 94 | + (instancetype)databaseQueueWithPath:(NSString*)aPath; 95 | 96 | /** Create queue using path and specified flags. 97 | 98 | @param aPath The file path of the database. 99 | @param openFlags Flags passed to the openWithFlags method of the database 100 | 101 | @return The `FMDatabaseQueue` object. `nil` on error. 102 | */ 103 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; 104 | 105 | /** Create queue using path. 106 | 107 | @param aPath The file path of the database. 108 | 109 | @return The `FMDatabaseQueue` object. `nil` on error. 110 | */ 111 | 112 | - (instancetype)initWithPath:(NSString*)aPath; 113 | 114 | /** Create queue using path and specified flags. 115 | 116 | @param aPath The file path of the database. 117 | @param openFlags Flags passed to the openWithFlags method of the database 118 | 119 | @return The `FMDatabaseQueue` object. `nil` on error. 120 | */ 121 | 122 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 123 | 124 | /** Create queue using path and specified flags. 125 | 126 | @param aPath The file path of the database. 127 | @param openFlags Flags passed to the openWithFlags method of the database 128 | @param vfsName The name of a custom virtual file system 129 | 130 | @return The `FMDatabaseQueue` object. `nil` on error. 131 | */ 132 | 133 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName; 134 | 135 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 136 | 137 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 138 | 139 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 140 | */ 141 | 142 | + (Class)databaseClass; 143 | 144 | /** Close database used by queue. */ 145 | 146 | - (void)close; 147 | 148 | /** Interupt pending database operation. */ 149 | 150 | - (void)interrupt; 151 | 152 | ///----------------------------------------------- 153 | /// @name Dispatching database operations to queue 154 | ///----------------------------------------------- 155 | 156 | /** Synchronously perform database operations on queue. 157 | 158 | @param block The code to be run on the queue of `FMDatabaseQueue` 159 | */ 160 | 161 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 162 | 163 | /** Synchronously perform database operations on queue, using transactions. 164 | 165 | @param block The code to be run on the queue of `FMDatabaseQueue` 166 | */ 167 | 168 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 169 | 170 | /** Synchronously perform database operations on queue, using deferred transactions. 171 | 172 | @param block The code to be run on the queue of `FMDatabaseQueue` 173 | */ 174 | 175 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 176 | 177 | ///----------------------------------------------- 178 | /// @name Dispatching database operations to queue 179 | ///----------------------------------------------- 180 | 181 | /** Synchronously perform database operations using save point. 182 | 183 | @param block The code to be run on the queue of `FMDatabaseQueue` 184 | */ 185 | 186 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 187 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 188 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 189 | 190 | @end 191 | 192 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMDatabaseQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabase.h" 11 | 12 | #if FMDB_SQLITE_STANDALONE 13 | #import 14 | #else 15 | #import 16 | #endif 17 | 18 | /* 19 | 20 | Note: we call [self retain]; before using dispatch_sync, just incase 21 | FMDatabaseQueue is released on another thread and we're in the middle of doing 22 | something in dispatch_sync 23 | 24 | */ 25 | 26 | /* 27 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. 28 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on 29 | * the queue's dispatch queue, which should not happen and causes a deadlock. 30 | */ 31 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; 32 | 33 | @implementation FMDatabaseQueue 34 | 35 | @synthesize path = _path; 36 | @synthesize openFlags = _openFlags; 37 | @synthesize vfsName = _vfsName; 38 | 39 | + (instancetype)databaseQueueWithPath:(NSString*)aPath { 40 | 41 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 42 | 43 | FMDBAutorelease(q); 44 | 45 | return q; 46 | } 47 | 48 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { 49 | 50 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 51 | 52 | FMDBAutorelease(q); 53 | 54 | return q; 55 | } 56 | 57 | + (Class)databaseClass { 58 | return [FMDatabase class]; 59 | } 60 | 61 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 62 | 63 | self = [super init]; 64 | 65 | if (self != nil) { 66 | 67 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 68 | FMDBRetain(_db); 69 | 70 | #if SQLITE_VERSION_NUMBER >= 3005000 71 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; 72 | #else 73 | BOOL success = [_db open]; 74 | #endif 75 | if (!success) { 76 | NSLog(@"Could not create database queue for path %@", aPath); 77 | FMDBRelease(self); 78 | return 0x00; 79 | } 80 | 81 | _path = FMDBReturnRetained(aPath); 82 | 83 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 84 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 85 | _openFlags = openFlags; 86 | _vfsName = [vfsName copy]; 87 | } 88 | 89 | return self; 90 | } 91 | 92 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 93 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 94 | } 95 | 96 | - (instancetype)initWithPath:(NSString*)aPath { 97 | 98 | // default flags for sqlite3_open 99 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; 100 | } 101 | 102 | - (instancetype)init { 103 | return [self initWithPath:nil]; 104 | } 105 | 106 | 107 | - (void)dealloc { 108 | 109 | FMDBRelease(_db); 110 | FMDBRelease(_path); 111 | 112 | if (_queue) { 113 | FMDBDispatchQueueRelease(_queue); 114 | _queue = 0x00; 115 | } 116 | #if ! __has_feature(objc_arc) 117 | [super dealloc]; 118 | #endif 119 | } 120 | 121 | - (void)close { 122 | FMDBRetain(self); 123 | dispatch_sync(_queue, ^() { 124 | [self->_db close]; 125 | FMDBRelease(_db); 126 | self->_db = 0x00; 127 | }); 128 | FMDBRelease(self); 129 | } 130 | 131 | - (void)interrupt 132 | { 133 | [[self database] interrupt]; 134 | } 135 | 136 | - (FMDatabase*)database { 137 | if (!_db) { 138 | _db = FMDBReturnRetained([[[self class] databaseClass] databaseWithPath:_path]); 139 | 140 | #if SQLITE_VERSION_NUMBER >= 3005000 141 | BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName]; 142 | #else 143 | BOOL success = [_db open]; 144 | #endif 145 | if (!success) { 146 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 147 | FMDBRelease(_db); 148 | _db = 0x00; 149 | return 0x00; 150 | } 151 | } 152 | 153 | return _db; 154 | } 155 | 156 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 157 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 158 | * and then check it against self to make sure we're not about to deadlock. */ 159 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 160 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 161 | 162 | FMDBRetain(self); 163 | 164 | dispatch_sync(_queue, ^() { 165 | 166 | FMDatabase *db = [self database]; 167 | block(db); 168 | 169 | if ([db hasOpenResultSets]) { 170 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 171 | 172 | #if defined(DEBUG) && DEBUG 173 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 174 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 175 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 176 | NSLog(@"query: '%@'", [rs query]); 177 | } 178 | #endif 179 | } 180 | }); 181 | 182 | FMDBRelease(self); 183 | } 184 | 185 | 186 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 187 | FMDBRetain(self); 188 | dispatch_sync(_queue, ^() { 189 | 190 | BOOL shouldRollback = NO; 191 | 192 | if (useDeferred) { 193 | [[self database] beginDeferredTransaction]; 194 | } 195 | else { 196 | [[self database] beginTransaction]; 197 | } 198 | 199 | block([self database], &shouldRollback); 200 | 201 | if (shouldRollback) { 202 | [[self database] rollback]; 203 | } 204 | else { 205 | [[self database] commit]; 206 | } 207 | }); 208 | 209 | FMDBRelease(self); 210 | } 211 | 212 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 213 | [self beginTransaction:YES withBlock:block]; 214 | } 215 | 216 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 217 | [self beginTransaction:NO withBlock:block]; 218 | } 219 | 220 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 221 | #if SQLITE_VERSION_NUMBER >= 3007000 222 | static unsigned long savePointIdx = 0; 223 | __block NSError *err = 0x00; 224 | FMDBRetain(self); 225 | dispatch_sync(_queue, ^() { 226 | 227 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 228 | 229 | BOOL shouldRollback = NO; 230 | 231 | if ([[self database] startSavePointWithName:name error:&err]) { 232 | 233 | block([self database], &shouldRollback); 234 | 235 | if (shouldRollback) { 236 | // We need to rollback and release this savepoint to remove it 237 | [[self database] rollbackToSavePointWithName:name error:&err]; 238 | } 239 | [[self database] releaseSavePointWithName:name error:&err]; 240 | 241 | } 242 | }); 243 | FMDBRelease(self); 244 | return err; 245 | #else 246 | NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); 247 | if (self.logsErrors) NSLog(@"%@", errorMessage); 248 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 249 | #endif 250 | } 251 | 252 | @end 253 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMResultSet.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #ifndef __has_feature // Optional. 4 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 5 | #endif 6 | 7 | #ifndef NS_RETURNS_NOT_RETAINED 8 | #if __has_feature(attribute_ns_returns_not_retained) 9 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) 10 | #else 11 | #define NS_RETURNS_NOT_RETAINED 12 | #endif 13 | #endif 14 | 15 | @class FMDatabase; 16 | @class FMStatement; 17 | 18 | /** Represents the results of executing a query on an ``. 19 | 20 | ### See also 21 | 22 | - `` 23 | */ 24 | 25 | @interface FMResultSet : NSObject { 26 | FMDatabase *_parentDB; 27 | FMStatement *_statement; 28 | 29 | NSString *_query; 30 | NSMutableDictionary *_columnNameToIndexMap; 31 | } 32 | 33 | ///----------------- 34 | /// @name Properties 35 | ///----------------- 36 | 37 | /** Executed query */ 38 | 39 | @property (atomic, retain) NSString *query; 40 | 41 | /** `NSMutableDictionary` mapping column names to numeric index */ 42 | 43 | @property (readonly) NSMutableDictionary *columnNameToIndexMap; 44 | 45 | /** `FMStatement` used by result set. */ 46 | 47 | @property (atomic, retain) FMStatement *statement; 48 | 49 | ///------------------------------------ 50 | /// @name Creating and closing database 51 | ///------------------------------------ 52 | 53 | /** Create result set from `` 54 | 55 | @param statement A `` to be performed 56 | 57 | @param aDB A `` to be used 58 | 59 | @return A `FMResultSet` on success; `nil` on failure 60 | */ 61 | 62 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; 63 | 64 | /** Close result set */ 65 | 66 | - (void)close; 67 | 68 | - (void)setParentDB:(FMDatabase *)newDb; 69 | 70 | ///--------------------------------------- 71 | /// @name Iterating through the result set 72 | ///--------------------------------------- 73 | 74 | /** Retrieve next row for result set. 75 | 76 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 77 | 78 | @return `YES` if row successfully retrieved; `NO` if end of result set reached 79 | 80 | @see hasAnotherRow 81 | */ 82 | 83 | - (BOOL)next; 84 | 85 | /** Retrieve next row for result set. 86 | 87 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 88 | 89 | @param outErr A 'NSError' object to receive any error object (if any). 90 | 91 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached 92 | 93 | @see hasAnotherRow 94 | */ 95 | 96 | - (BOOL)nextWithError:(NSError **)outErr; 97 | 98 | /** Did the last call to `` succeed in retrieving another row? 99 | 100 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. 101 | 102 | @see next 103 | 104 | @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. 105 | */ 106 | 107 | - (BOOL)hasAnotherRow; 108 | 109 | ///--------------------------------------------- 110 | /// @name Retrieving information from result set 111 | ///--------------------------------------------- 112 | 113 | /** How many columns in result set 114 | 115 | @return Integer value of the number of columns. 116 | */ 117 | 118 | - (int)columnCount; 119 | 120 | /** Column index for column name 121 | 122 | @param columnName `NSString` value of the name of the column. 123 | 124 | @return Zero-based index for column. 125 | */ 126 | 127 | - (int)columnIndexForName:(NSString*)columnName; 128 | 129 | /** Column name for column index 130 | 131 | @param columnIdx Zero-based index for column. 132 | 133 | @return columnName `NSString` value of the name of the column. 134 | */ 135 | 136 | - (NSString*)columnNameForIndex:(int)columnIdx; 137 | 138 | /** Result set integer value for column. 139 | 140 | @param columnName `NSString` value of the name of the column. 141 | 142 | @return `int` value of the result set's column. 143 | */ 144 | 145 | - (int)intForColumn:(NSString*)columnName; 146 | 147 | /** Result set integer value for column. 148 | 149 | @param columnIdx Zero-based index for column. 150 | 151 | @return `int` value of the result set's column. 152 | */ 153 | 154 | - (int)intForColumnIndex:(int)columnIdx; 155 | 156 | /** Result set `long` value for column. 157 | 158 | @param columnName `NSString` value of the name of the column. 159 | 160 | @return `long` value of the result set's column. 161 | */ 162 | 163 | - (long)longForColumn:(NSString*)columnName; 164 | 165 | /** Result set long value for column. 166 | 167 | @param columnIdx Zero-based index for column. 168 | 169 | @return `long` value of the result set's column. 170 | */ 171 | 172 | - (long)longForColumnIndex:(int)columnIdx; 173 | 174 | /** Result set `long long int` value for column. 175 | 176 | @param columnName `NSString` value of the name of the column. 177 | 178 | @return `long long int` value of the result set's column. 179 | */ 180 | 181 | - (long long int)longLongIntForColumn:(NSString*)columnName; 182 | 183 | /** Result set `long long int` value for column. 184 | 185 | @param columnIdx Zero-based index for column. 186 | 187 | @return `long long int` value of the result set's column. 188 | */ 189 | 190 | - (long long int)longLongIntForColumnIndex:(int)columnIdx; 191 | 192 | /** Result set `unsigned long long int` value for column. 193 | 194 | @param columnName `NSString` value of the name of the column. 195 | 196 | @return `unsigned long long int` value of the result set's column. 197 | */ 198 | 199 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; 200 | 201 | /** Result set `unsigned long long int` value for column. 202 | 203 | @param columnIdx Zero-based index for column. 204 | 205 | @return `unsigned long long int` value of the result set's column. 206 | */ 207 | 208 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; 209 | 210 | /** Result set `BOOL` value for column. 211 | 212 | @param columnName `NSString` value of the name of the column. 213 | 214 | @return `BOOL` value of the result set's column. 215 | */ 216 | 217 | - (BOOL)boolForColumn:(NSString*)columnName; 218 | 219 | /** Result set `BOOL` value for column. 220 | 221 | @param columnIdx Zero-based index for column. 222 | 223 | @return `BOOL` value of the result set's column. 224 | */ 225 | 226 | - (BOOL)boolForColumnIndex:(int)columnIdx; 227 | 228 | /** Result set `double` value for column. 229 | 230 | @param columnName `NSString` value of the name of the column. 231 | 232 | @return `double` value of the result set's column. 233 | 234 | */ 235 | 236 | - (double)doubleForColumn:(NSString*)columnName; 237 | 238 | /** Result set `double` value for column. 239 | 240 | @param columnIdx Zero-based index for column. 241 | 242 | @return `double` value of the result set's column. 243 | 244 | */ 245 | 246 | - (double)doubleForColumnIndex:(int)columnIdx; 247 | 248 | /** Result set `NSString` value for column. 249 | 250 | @param columnName `NSString` value of the name of the column. 251 | 252 | @return `NSString` value of the result set's column. 253 | 254 | */ 255 | 256 | - (NSString*)stringForColumn:(NSString*)columnName; 257 | 258 | /** Result set `NSString` value for column. 259 | 260 | @param columnIdx Zero-based index for column. 261 | 262 | @return `NSString` value of the result set's column. 263 | */ 264 | 265 | - (NSString*)stringForColumnIndex:(int)columnIdx; 266 | 267 | /** Result set `NSDate` value for column. 268 | 269 | @param columnName `NSString` value of the name of the column. 270 | 271 | @return `NSDate` value of the result set's column. 272 | */ 273 | 274 | - (NSDate*)dateForColumn:(NSString*)columnName; 275 | 276 | /** Result set `NSDate` value for column. 277 | 278 | @param columnIdx Zero-based index for column. 279 | 280 | @return `NSDate` value of the result set's column. 281 | 282 | */ 283 | 284 | - (NSDate*)dateForColumnIndex:(int)columnIdx; 285 | 286 | /** Result set `NSData` value for column. 287 | 288 | This is useful when storing binary data in table (such as image or the like). 289 | 290 | @param columnName `NSString` value of the name of the column. 291 | 292 | @return `NSData` value of the result set's column. 293 | 294 | */ 295 | 296 | - (NSData*)dataForColumn:(NSString*)columnName; 297 | 298 | /** Result set `NSData` value for column. 299 | 300 | @param columnIdx Zero-based index for column. 301 | 302 | @return `NSData` value of the result set's column. 303 | */ 304 | 305 | - (NSData*)dataForColumnIndex:(int)columnIdx; 306 | 307 | /** Result set `(const unsigned char *)` value for column. 308 | 309 | @param columnName `NSString` value of the name of the column. 310 | 311 | @return `(const unsigned char *)` value of the result set's column. 312 | */ 313 | 314 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; 315 | 316 | /** Result set `(const unsigned char *)` value for column. 317 | 318 | @param columnIdx Zero-based index for column. 319 | 320 | @return `(const unsigned char *)` value of the result set's column. 321 | */ 322 | 323 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; 324 | 325 | /** Result set object for column. 326 | 327 | @param columnName `NSString` value of the name of the column. 328 | 329 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 330 | 331 | @see objectForKeyedSubscript: 332 | */ 333 | 334 | - (id)objectForColumnName:(NSString*)columnName; 335 | 336 | /** Result set object for column. 337 | 338 | @param columnIdx Zero-based index for column. 339 | 340 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 341 | 342 | @see objectAtIndexedSubscript: 343 | */ 344 | 345 | - (id)objectForColumnIndex:(int)columnIdx; 346 | 347 | /** Result set object for column. 348 | 349 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 350 | 351 | id result = rs[@"employee_name"]; 352 | 353 | This simplified syntax is equivalent to calling: 354 | 355 | id result = [rs objectForKeyedSubscript:@"employee_name"]; 356 | 357 | which is, it turns out, equivalent to calling: 358 | 359 | id result = [rs objectForColumnName:@"employee_name"]; 360 | 361 | @param columnName `NSString` value of the name of the column. 362 | 363 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 364 | */ 365 | 366 | - (id)objectForKeyedSubscript:(NSString *)columnName; 367 | 368 | /** Result set object for column. 369 | 370 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 371 | 372 | id result = rs[0]; 373 | 374 | This simplified syntax is equivalent to calling: 375 | 376 | id result = [rs objectForKeyedSubscript:0]; 377 | 378 | which is, it turns out, equivalent to calling: 379 | 380 | id result = [rs objectForColumnName:0]; 381 | 382 | @param columnIdx Zero-based index for column. 383 | 384 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 385 | */ 386 | 387 | - (id)objectAtIndexedSubscript:(int)columnIdx; 388 | 389 | /** Result set `NSData` value for column. 390 | 391 | @param columnName `NSString` value of the name of the column. 392 | 393 | @return `NSData` value of the result set's column. 394 | 395 | @warning If you are going to use this data after you iterate over the next row, or after you close the 396 | result set, make sure to make a copy of the data first (or just use ``/``) 397 | If you don't, you're going to be in a world of hurt when you try and use the data. 398 | 399 | */ 400 | 401 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; 402 | 403 | /** Result set `NSData` value for column. 404 | 405 | @param columnIdx Zero-based index for column. 406 | 407 | @return `NSData` value of the result set's column. 408 | 409 | @warning If you are going to use this data after you iterate over the next row, or after you close the 410 | result set, make sure to make a copy of the data first (or just use ``/``) 411 | If you don't, you're going to be in a world of hurt when you try and use the data. 412 | 413 | */ 414 | 415 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; 416 | 417 | /** Is the column `NULL`? 418 | 419 | @param columnIdx Zero-based index for column. 420 | 421 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 422 | */ 423 | 424 | - (BOOL)columnIndexIsNull:(int)columnIdx; 425 | 426 | /** Is the column `NULL`? 427 | 428 | @param columnName `NSString` value of the name of the column. 429 | 430 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 431 | */ 432 | 433 | - (BOOL)columnIsNull:(NSString*)columnName; 434 | 435 | 436 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names. 437 | 438 | @returns `NSDictionary` of the row results. 439 | 440 | @warning The keys to the dictionary are case sensitive of the column names. 441 | */ 442 | 443 | - (NSDictionary*)resultDictionary; 444 | 445 | /** Returns a dictionary of the row results 446 | 447 | @see resultDictionary 448 | 449 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! 450 | */ 451 | 452 | - (NSDictionary*)resultDict __attribute__ ((deprecated)); 453 | 454 | ///----------------------------- 455 | /// @name Key value coding magic 456 | ///----------------------------- 457 | 458 | /** Performs `setValue` to yield support for key value observing. 459 | 460 | @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. 461 | 462 | */ 463 | 464 | - (void)kvcMagic:(id)object; 465 | 466 | 467 | @end 468 | 469 | -------------------------------------------------------------------------------- /Calculator1/fmdb/FMResultSet.m: -------------------------------------------------------------------------------- 1 | #import "FMResultSet.h" 2 | #import "FMDatabase.h" 3 | #import "unistd.h" 4 | 5 | #if FMDB_SQLITE_STANDALONE 6 | #import 7 | #else 8 | #import 9 | #endif 10 | 11 | @interface FMDatabase () 12 | - (void)resultSetDidClose:(FMResultSet *)resultSet; 13 | @end 14 | 15 | 16 | @implementation FMResultSet 17 | @synthesize query=_query; 18 | @synthesize statement=_statement; 19 | 20 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { 21 | 22 | FMResultSet *rs = [[FMResultSet alloc] init]; 23 | 24 | [rs setStatement:statement]; 25 | [rs setParentDB:aDB]; 26 | 27 | NSParameterAssert(![statement inUse]); 28 | [statement setInUse:YES]; // weak reference 29 | 30 | return FMDBReturnAutoreleased(rs); 31 | } 32 | 33 | - (void)finalize { 34 | [self close]; 35 | [super finalize]; 36 | } 37 | 38 | - (void)dealloc { 39 | [self close]; 40 | 41 | FMDBRelease(_query); 42 | _query = nil; 43 | 44 | FMDBRelease(_columnNameToIndexMap); 45 | _columnNameToIndexMap = nil; 46 | 47 | #if ! __has_feature(objc_arc) 48 | [super dealloc]; 49 | #endif 50 | } 51 | 52 | - (void)close { 53 | [_statement reset]; 54 | FMDBRelease(_statement); 55 | _statement = nil; 56 | 57 | // we don't need this anymore... (i think) 58 | //[_parentDB setInUse:NO]; 59 | [_parentDB resultSetDidClose:self]; 60 | _parentDB = nil; 61 | } 62 | 63 | - (int)columnCount { 64 | return sqlite3_column_count([_statement statement]); 65 | } 66 | 67 | - (NSMutableDictionary *)columnNameToIndexMap { 68 | if (!_columnNameToIndexMap) { 69 | int columnCount = sqlite3_column_count([_statement statement]); 70 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; 71 | int columnIdx = 0; 72 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 73 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] 74 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; 75 | } 76 | } 77 | return _columnNameToIndexMap; 78 | } 79 | 80 | - (void)kvcMagic:(id)object { 81 | 82 | int columnCount = sqlite3_column_count([_statement statement]); 83 | 84 | int columnIdx = 0; 85 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 86 | 87 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 88 | 89 | // check for a null row 90 | if (c) { 91 | NSString *s = [NSString stringWithUTF8String:c]; 92 | 93 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; 94 | } 95 | } 96 | } 97 | 98 | #pragma clang diagnostic push 99 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 100 | 101 | - (NSDictionary*)resultDict { 102 | 103 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 104 | 105 | if (num_cols > 0) { 106 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 107 | 108 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; 109 | NSString *columnName = nil; 110 | while ((columnName = [columnNames nextObject])) { 111 | id objectValue = [self objectForColumnName:columnName]; 112 | [dict setObject:objectValue forKey:columnName]; 113 | } 114 | 115 | return FMDBReturnAutoreleased([dict copy]); 116 | } 117 | else { 118 | NSLog(@"Warning: There seem to be no columns in this set."); 119 | } 120 | 121 | return nil; 122 | } 123 | 124 | #pragma clang diagnostic pop 125 | 126 | - (NSDictionary*)resultDictionary { 127 | 128 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 129 | 130 | if (num_cols > 0) { 131 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 132 | 133 | int columnCount = sqlite3_column_count([_statement statement]); 134 | 135 | int columnIdx = 0; 136 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 137 | 138 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; 139 | id objectValue = [self objectForColumnIndex:columnIdx]; 140 | [dict setObject:objectValue forKey:columnName]; 141 | } 142 | 143 | return dict; 144 | } 145 | else { 146 | NSLog(@"Warning: There seem to be no columns in this set."); 147 | } 148 | 149 | return nil; 150 | } 151 | 152 | 153 | 154 | 155 | - (BOOL)next { 156 | return [self nextWithError:nil]; 157 | } 158 | 159 | - (BOOL)nextWithError:(NSError **)outErr { 160 | 161 | int rc = sqlite3_step([_statement statement]); 162 | 163 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { 164 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); 165 | NSLog(@"Database busy"); 166 | if (outErr) { 167 | *outErr = [_parentDB lastError]; 168 | } 169 | } 170 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { 171 | // all is well, let's return. 172 | } 173 | else if (SQLITE_ERROR == rc) { 174 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 175 | if (outErr) { 176 | *outErr = [_parentDB lastError]; 177 | } 178 | } 179 | else if (SQLITE_MISUSE == rc) { 180 | // uh oh. 181 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 182 | if (outErr) { 183 | if (_parentDB) { 184 | *outErr = [_parentDB lastError]; 185 | } 186 | else { 187 | // If 'next' or 'nextWithError' is called after the result set is closed, 188 | // we need to return the appropriate error. 189 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; 190 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; 191 | } 192 | 193 | } 194 | } 195 | else { 196 | // wtf? 197 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 198 | if (outErr) { 199 | *outErr = [_parentDB lastError]; 200 | } 201 | } 202 | 203 | 204 | if (rc != SQLITE_ROW) { 205 | [self close]; 206 | } 207 | 208 | return (rc == SQLITE_ROW); 209 | } 210 | 211 | - (BOOL)hasAnotherRow { 212 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; 213 | } 214 | 215 | - (int)columnIndexForName:(NSString*)columnName { 216 | columnName = [columnName lowercaseString]; 217 | 218 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; 219 | 220 | if (n) { 221 | return [n intValue]; 222 | } 223 | 224 | NSLog(@"Warning: I could not find the column named '%@'.", columnName); 225 | 226 | return -1; 227 | } 228 | 229 | 230 | 231 | - (int)intForColumn:(NSString*)columnName { 232 | return [self intForColumnIndex:[self columnIndexForName:columnName]]; 233 | } 234 | 235 | - (int)intForColumnIndex:(int)columnIdx { 236 | return sqlite3_column_int([_statement statement], columnIdx); 237 | } 238 | 239 | - (long)longForColumn:(NSString*)columnName { 240 | return [self longForColumnIndex:[self columnIndexForName:columnName]]; 241 | } 242 | 243 | - (long)longForColumnIndex:(int)columnIdx { 244 | return (long)sqlite3_column_int64([_statement statement], columnIdx); 245 | } 246 | 247 | - (long long int)longLongIntForColumn:(NSString*)columnName { 248 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; 249 | } 250 | 251 | - (long long int)longLongIntForColumnIndex:(int)columnIdx { 252 | return sqlite3_column_int64([_statement statement], columnIdx); 253 | } 254 | 255 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { 256 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; 257 | } 258 | 259 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { 260 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; 261 | } 262 | 263 | - (BOOL)boolForColumn:(NSString*)columnName { 264 | return [self boolForColumnIndex:[self columnIndexForName:columnName]]; 265 | } 266 | 267 | - (BOOL)boolForColumnIndex:(int)columnIdx { 268 | return ([self intForColumnIndex:columnIdx] != 0); 269 | } 270 | 271 | - (double)doubleForColumn:(NSString*)columnName { 272 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; 273 | } 274 | 275 | - (double)doubleForColumnIndex:(int)columnIdx { 276 | return sqlite3_column_double([_statement statement], columnIdx); 277 | } 278 | 279 | - (NSString*)stringForColumnIndex:(int)columnIdx { 280 | 281 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 282 | return nil; 283 | } 284 | 285 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 286 | 287 | if (!c) { 288 | // null row. 289 | return nil; 290 | } 291 | 292 | return [NSString stringWithUTF8String:c]; 293 | } 294 | 295 | - (NSString*)stringForColumn:(NSString*)columnName { 296 | return [self stringForColumnIndex:[self columnIndexForName:columnName]]; 297 | } 298 | 299 | - (NSDate*)dateForColumn:(NSString*)columnName { 300 | return [self dateForColumnIndex:[self columnIndexForName:columnName]]; 301 | } 302 | 303 | - (NSDate*)dateForColumnIndex:(int)columnIdx { 304 | 305 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 306 | return nil; 307 | } 308 | 309 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; 310 | } 311 | 312 | 313 | - (NSData*)dataForColumn:(NSString*)columnName { 314 | return [self dataForColumnIndex:[self columnIndexForName:columnName]]; 315 | } 316 | 317 | - (NSData*)dataForColumnIndex:(int)columnIdx { 318 | 319 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 320 | return nil; 321 | } 322 | 323 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 324 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 325 | 326 | if (dataBuffer == NULL) { 327 | return nil; 328 | } 329 | 330 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; 331 | } 332 | 333 | 334 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName { 335 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; 336 | } 337 | 338 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { 339 | 340 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 341 | return nil; 342 | } 343 | 344 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 345 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 346 | 347 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; 348 | 349 | return data; 350 | } 351 | 352 | 353 | - (BOOL)columnIndexIsNull:(int)columnIdx { 354 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; 355 | } 356 | 357 | - (BOOL)columnIsNull:(NSString*)columnName { 358 | return [self columnIndexIsNull:[self columnIndexForName:columnName]]; 359 | } 360 | 361 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { 362 | 363 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 364 | return nil; 365 | } 366 | 367 | return sqlite3_column_text([_statement statement], columnIdx); 368 | } 369 | 370 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { 371 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; 372 | } 373 | 374 | - (id)objectForColumnIndex:(int)columnIdx { 375 | int columnType = sqlite3_column_type([_statement statement], columnIdx); 376 | 377 | id returnValue = nil; 378 | 379 | if (columnType == SQLITE_INTEGER) { 380 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; 381 | } 382 | else if (columnType == SQLITE_FLOAT) { 383 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; 384 | } 385 | else if (columnType == SQLITE_BLOB) { 386 | returnValue = [self dataForColumnIndex:columnIdx]; 387 | } 388 | else { 389 | //default to a string for everything else 390 | returnValue = [self stringForColumnIndex:columnIdx]; 391 | } 392 | 393 | if (returnValue == nil) { 394 | returnValue = [NSNull null]; 395 | } 396 | 397 | return returnValue; 398 | } 399 | 400 | - (id)objectForColumnName:(NSString*)columnName { 401 | return [self objectForColumnIndex:[self columnIndexForName:columnName]]; 402 | } 403 | 404 | // returns autoreleased NSString containing the name of the column in the result set 405 | - (NSString*)columnNameForIndex:(int)columnIdx { 406 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; 407 | } 408 | 409 | - (void)setParentDB:(FMDatabase *)newDb { 410 | _parentDB = newDb; 411 | } 412 | 413 | - (id)objectAtIndexedSubscript:(int)columnIdx { 414 | return [self objectForColumnIndex:columnIdx]; 415 | } 416 | 417 | - (id)objectForKeyedSubscript:(NSString *)columnName { 418 | return [self objectForColumnName:columnName]; 419 | } 420 | 421 | 422 | @end 423 | -------------------------------------------------------------------------------- /Calculator1/fmdb/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.6.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Calculator1/historyTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // historyTableViewCell.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/22. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMResultSet.h" 11 | 12 | 13 | @interface historyTableViewCell : UITableViewCell 14 | @property (weak, nonatomic) IBOutlet UILabel *yearLable; 15 | @property (weak, nonatomic) IBOutlet UILabel *monthLable; 16 | @property (weak, nonatomic) IBOutlet UILabel *infoLable; 17 | @property (weak, nonatomic) IBOutlet UILabel *mathResultLable; 18 | 19 | -(id)initWithData:(NSDictionary *)info tableView:tableView; 20 | @end 21 | -------------------------------------------------------------------------------- /Calculator1/historyTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // historyTableViewCell.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/22. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "historyTableViewCell.h" 10 | 11 | @implementation historyTableViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | } 16 | 17 | //- (void)setSelected:(BOOL)selected animated:(BOOL)animated { 18 | // [super setSelected:selected animated:animated]; 19 | //} 20 | -(id)initWithData:(NSDictionary *)info tableView:(id)tableView{ 21 | static NSString *CellIdentifier=@"CallId"; 22 | self=[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 23 | if (self==nil) { 24 | self=[[[NSBundle mainBundle] loadNibNamed:@"historyTableViewCell" owner:self options:nil]lastObject]; 25 | } 26 | // NSDictionary *dic=@{@"ID":IDStr,@"time":time,@"beforeNub":beforeNub,@"operationType":operationType,@"currentNub":currentNub,@"ResultStr":ResultStr}; 27 | self.infoLable.text=[NSString stringWithFormat:@"%@ %@ %@=",info[@"beforeNub"],info[@"operationType"],info[@"currentNub"]] ; 28 | self.mathResultLable.text=info[@"ResultStr"]; 29 | int time=[info[@"time"] intValue];//转换成整型 30 | self.yearLable.text = [self date:time formate:@"YYYY"]; 31 | self.monthLable.text = [self date:time formate:@"M月d"]; 32 | return self; 33 | } 34 | -(NSString *)date:(int)time formate:(NSString *)formate{ 35 | NSDate * date = [NSDate dateWithTimeIntervalSince1970:time]; 36 | NSDateFormatter * formatter = [[NSDateFormatter alloc ]init]; 37 | [formatter setDateFormat:formate]; 38 | return [formatter stringFromDate:date]; 39 | } 40 | 41 | 42 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 43 | //[super setSelected:selected animated:animated]; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /Calculator1/historyTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 28 | 34 | 35 | 36 | 37 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Calculator1/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Calculator1/savehistoryData.h: -------------------------------------------------------------------------------- 1 | // 2 | // savehistoryData.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/6/21. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | #import "FMResultSet.h" 12 | @interface savehistoryData : NSObject 13 | 14 | @property (strong, nonatomic) NSString *test; 15 | @property (strong,nonatomic)FMDatabase *db; 16 | 17 | 18 | +(void)historyAdd:(NSString *)curretTime beforeNum:(NSString *)beforeNub operationType:(NSString *)operationType CurrentNub:(NSString *)currentNub result:(NSString *)resultdate; 19 | +(NSMutableArray *)seachHistoryData; 20 | +(void)deleteAllHistory; 21 | +(void)deleteSelectHistory:(NSString *)IDStr; 22 | @end 23 | -------------------------------------------------------------------------------- /Calculator1/savehistoryData.m: -------------------------------------------------------------------------------- 1 | // 2 | // savehistoryData.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/6/21. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "savehistoryData.h" 10 | 11 | @implementation savehistoryData{ 12 | int index; 13 | } 14 | //-(void)initSaveHistoryData{ 15 | // index = 10; 16 | // self.test = @"asdf"; 17 | //} 18 | //-(void)setTheIndex:(int)set{ 19 | // index = set; 20 | //} 21 | //-(int)getTheIndex{ 22 | // return index; 23 | //} 24 | //+(void)pageNext{ 25 | // savehistoryData * temp = [savehistoryData sharedInstance]; 26 | // temp.test = @"asdf"; 27 | // [temp setTheIndex:[temp getTheIndex]+1]; 28 | //} 29 | //+(void)pageUp{ 30 | // savehistoryData * temp = [savehistoryData sharedInstance]; 31 | // temp.test = @"asdf"; 32 | // [temp setTheIndex:[temp getTheIndex]-1]; 33 | //} 34 | +(instancetype)sharedInstance{ 35 | static savehistoryData * singleton = nil; 36 | static dispatch_once_t onceToken; 37 | dispatch_once(&onceToken, ^{ 38 | singleton = [[self alloc] init]; 39 | // [singleton initSaveHistoryData]; 40 | [singleton getFmdbBase]; 41 | }); 42 | return singleton; 43 | } 44 | -(FMDatabase *)getFmdbBase{ 45 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 46 | NSString *documentDirectory = [paths objectAtIndex:0]; 47 | NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"historyData.db"]; 48 | self.db = [FMDatabase databaseWithPath:dbPath]; 49 | [self.db open]; 50 | [self.db executeUpdate:@"CREATE TABLE historyTable (ID integer primary key autoincrement,time integer,beforeNub text, operationType text,CurrentNub text,result text)"]; 51 | return self.db; 52 | } 53 | 54 | +(void)historyAdd:(NSString *)curretTime beforeNum:(NSString *)beforeNub operationType:(NSString *)operationType CurrentNub:(NSString *)currentNub result:(NSString *)resultdate{ 55 | savehistoryData *His=[savehistoryData sharedInstance]; 56 | [His.db executeUpdate:@"INSERT INTO historyTable (time,beforeNub,operationType,CurrentNub,result) VALUES (?,?,?,?,?)",curretTime,beforeNub,operationType,currentNub, resultdate]; 57 | } 58 | #pragma mark 初始化加载历史记录数据 59 | +(NSMutableArray *)seachHistoryData{ 60 | NSMutableArray *history=[[NSMutableArray alloc]init]; 61 | savehistoryData *his=[savehistoryData sharedInstance]; 62 | FMResultSet *rs = [his.db executeQuery:@"SELECT * FROM historyTable"]; 63 | while ([rs next]) { 64 | int ID=[rs intForColumn:@"ID"]; 65 | NSString *IDStr=[NSString stringWithFormat:@"%d",ID]; 66 | NSString *time=[rs stringForColumn:@"time"]; 67 | NSString *beforeNub=[rs stringForColumn:@"beforeNub"]; 68 | NSString *operationType = [rs stringForColumn:@"operationType"]; 69 | NSString *currentNub=[rs stringForColumn:@"currentNub"]; 70 | NSString *ResultStr = [rs stringForColumn:@"result"]; 71 | NSDictionary *dic=@{@"ID":IDStr,@"time":time,@"beforeNub":beforeNub,@"operationType":operationType,@"currentNub":currentNub,@"ResultStr":ResultStr}; 72 | [history insertObject:dic atIndex:0]; 73 | } 74 | [rs close]; 75 | return history; 76 | } 77 | +(void)deleteAllHistory{ 78 | savehistoryData *his=[savehistoryData sharedInstance]; 79 | [his.db executeUpdate:@"DELETE FROM historyTable"]; 80 | } 81 | +(void)deleteSelectHistory:(NSString *)IDStr{ 82 | savehistoryData *his=[savehistoryData sharedInstance]; 83 | [his.db executeUpdate:@"delete from historyTable where ID = ?",IDStr]; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /Calculator1/setViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // setViewController.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/25. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "Common.h" 11 | 12 | @interface setViewController : UIViewController 13 | 14 | - (IBAction)gotoBack:(id)sender; 15 | 16 | @property (assign,nonatomic) BOOL musicOn; 17 | - (IBAction)gotoTheme:(id)sender; 18 | - (IBAction)musicState:(id)sender; 19 | - (IBAction)clickMuisc1:(id)sender; 20 | - (IBAction)clickMuisc2:(id)sender; 21 | 22 | - (IBAction)clickMuisc3:(id)sender; 23 | @property (weak, nonatomic) IBOutlet UISwitch *MusicswitchSate; 24 | 25 | - (IBAction)clickMuisc4:(id)sender; 26 | - (IBAction)OponBlurEffect:(id)sender; 27 | @property (weak, nonatomic) IBOutlet UISwitch *blurEffectSatae; 28 | 29 | @property (weak, nonatomic) IBOutlet UIImageView *selectImage1; 30 | @property (weak, nonatomic) IBOutlet UIImageView *selectImage2; 31 | @property (weak, nonatomic) IBOutlet UIImageView *selectImage3; 32 | @property (weak, nonatomic) IBOutlet UIImageView *selectImage4; 33 | @end 34 | -------------------------------------------------------------------------------- /Calculator1/setViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // setViewController.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/25. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "setViewController.h" 10 | #import "themeViewController.h" 11 | #import 12 | 13 | 14 | @interface setViewController () 15 | 16 | 17 | 18 | @end 19 | 20 | @implementation setViewController{ 21 | NSMutableArray *clickMusic; 22 | int musicState; 23 | 24 | } 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | clickMusic=[[NSMutableArray alloc]init]; 29 | [clickMusic addObject:@"0"]; 30 | } 31 | 32 | - (void)didReceiveMemoryWarning { 33 | [super didReceiveMemoryWarning]; 34 | // Dispose of any resources that can be recreated. 35 | } 36 | #pragma mark 音效实现函数 37 | -(void)playSoundEffect:(NSString *)name{ 38 | NSString *audioFile=[[NSBundle mainBundle] pathForResource:name ofType:nil]; 39 | NSURL *fileUrl=[NSURL fileURLWithPath:audioFile]; 40 | SystemSoundID soundID=0;//获得系统声音ID 41 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID); 42 | AudioServicesPlaySystemSound(soundID);//播放音效 43 | } 44 | 45 | - (IBAction)gotoBack:(id)sender { 46 | [self.navigationController popViewControllerAnimated:true];//返回主界面 47 | } 48 | - (IBAction)gotoTheme:(id)sender { 49 | themeViewController *gotoThemePage=[[themeViewController alloc]init]; 50 | [self.navigationController pushViewController:gotoThemePage animated:YES]; 51 | } 52 | - (IBAction)musicState:(id)sender { 53 | UISwitch * swit= (UISwitch *)sender; 54 | NSString * ON =[NSString stringWithFormat:@"%d",swit.on]; 55 | [Common configSet:@"key_music_on" value:ON]; 56 | musicState=swit.on; 57 | } 58 | - (IBAction)OponBlurEffect:(id)sender{ 59 | UISwitch *swit1=(UISwitch *)sender; 60 | NSString *bgEffectOn=[NSString stringWithFormat:@"%d",swit1.on]; 61 | [Common configSet:@"key_bg_lurEffect_on" value:bgEffectOn]; 62 | NSLog( @"blurEffect%@",[Common configGet:@"key_bg_lurEffect_on"]); 63 | 64 | } 65 | -(void)viewWillAppear:(BOOL)animated{ 66 | musicState=[[Common configGet:@"key_music_on"]intValue]; 67 | int i; 68 | NSArray *array=[Common configGetClcikMusic:@"MusicKey"]; 69 | NSString *Str=[array objectAtIndex:0]; 70 | if ([Str isEqualToString:@"Music1"]) { 71 | i=1; 72 | }else if ([Str isEqualToString:@"Music2"]) { 73 | i=2; 74 | }else if ([Str isEqualToString:@"Music3"]) { 75 | i=3; 76 | }else if ([Str isEqualToString:@"Music4"]) { 77 | i=4; 78 | } 79 | switch (i) { 80 | case 1 :self.selectImage1.hidden=NO;break; 81 | case 2:self.selectImage2.hidden=NO;break; 82 | case 3:self.selectImage3.hidden=NO;break; 83 | case 4:self.selectImage4.hidden=NO;break; 84 | default:break; 85 | } 86 | if (musicState) { 87 | self.MusicswitchSate.on=YES; 88 | }else{ 89 | self.MusicswitchSate.on=NO; 90 | } 91 | if ([[Common configGet:@"key_bg_lurEffect_on"]intValue]) { 92 | self.blurEffectSatae.on=YES; 93 | }else{ 94 | self.blurEffectSatae.on=NO; 95 | } 96 | } 97 | - (IBAction)clickMuisc1:(id)sender { 98 | [clickMusic replaceObjectAtIndex:0 withObject:@"Music1"]; 99 | [self setSelectImageHidden]; 100 | self.selectImage1.hidden=NO; 101 | if (musicState) { 102 | [self playSoundEffect:@"click.wav"]; 103 | } 104 | [Common configSet:@"MusicKey" value:clickMusic]; 105 | } 106 | - (IBAction)clickMuisc2:(id)sender { 107 | [clickMusic replaceObjectAtIndex:0 withObject:@"Music2"]; 108 | [Common configSet:@"MusicKey" value:clickMusic]; 109 | if (musicState) { 110 | [self playSoundEffect:@"click1.wav"]; 111 | } 112 | [self setSelectImageHidden]; 113 | self.selectImage2.hidden=NO; 114 | } 115 | - (IBAction)clickMuisc3:(id)sender { 116 | [clickMusic replaceObjectAtIndex:0 withObject:@"Music3"]; 117 | [Common configSet:@"MusicKey" value:clickMusic]; 118 | if (musicState) { 119 | [self playSoundEffect:@"click2.wav"]; 120 | } 121 | [self setSelectImageHidden]; 122 | self.selectImage3.hidden=NO; 123 | } 124 | - (IBAction)clickMuisc4:(id)sender { 125 | [clickMusic replaceObjectAtIndex:0 withObject:@"Music4"]; 126 | [Common configSet:@"MusicKey" value:clickMusic]; 127 | if (musicState) { 128 | [self playSoundEffect:@"click3.wav"]; 129 | } 130 | [self setSelectImageHidden]; 131 | self.selectImage4.hidden=NO; 132 | } 133 | -(void)setSelectImageHidden{ 134 | self.selectImage1.hidden=YES; 135 | self.selectImage2.hidden=YES; 136 | self.selectImage3.hidden=YES; 137 | self.selectImage4.hidden=YES; 138 | 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /Calculator1/setViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 59 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 128 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 158 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 222 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /Calculator1/themeCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Calculator1/themeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // themeViewController.h 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/25. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "Common.h" 11 | #define IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0 ? YES : NO) 12 | 13 | @interface themeViewController : UIViewController 14 | - (IBAction)gotoBack:(id)sender; 15 | 16 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; 17 | @end 18 | -------------------------------------------------------------------------------- /Calculator1/themeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // themeViewController.m 3 | // Calculator1 4 | // 5 | // Created by ruru on 16/4/25. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import "themeViewController.h" 10 | #import "setViewController.h" 11 | 12 | #define RGB(color) [UIColor colorWithRed:(color>>16)/255.0 green:((color>>8)&0xff)/255.0 blue:(color&0xff)/255.0 alpha:1] 13 | #define RGBA(color,alpha) [UIColor colorWithRed:(color>>16)/255.0 green:((color>>8)&0xff)/255.0 blue:(color&0xff)/255.0 alpha:alpha] 14 | @interface themeViewController () 15 | 16 | @end 17 | 18 | @implementation themeViewController{ 19 | NSString *currentSelcetTheme; 20 | NSArray *themeArray; 21 | NSString *isSateDefine; 22 | } 23 | 24 | - (void)viewDidLoad { 25 | isSateDefine=nil; 26 | [super viewDidLoad]; 27 | NSDictionary *themeDic=[Common configGetTheme:@"key_setting_theme"]; 28 | 29 | if (!themeDic[@"theme_name"]) { 30 | currentSelcetTheme=@"默认"; 31 | }else{ 32 | currentSelcetTheme=themeDic[@"theme_name"]; 33 | } 34 | themeArray=[self loadTheme]; 35 | [self loadThemeList]; 36 | 37 | } 38 | -(NSArray *)loadTheme{ 39 | return @[@{ 40 | @"theme_name":@"默认", 41 | @"theme_icon_image":@"默认",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 42 | @"theme_background_color":@[@"0x223048",@"0.9"], 43 | @"button_background_color":@[@"0x6D7989",@"0.9"], 44 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 45 | @"font-color":@[@"0xC9CED5",@"1.0"], 46 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], 47 | 48 | }, 49 | @{ 50 | @"theme_name":@"高雅紫", 51 | @"theme_icon_image":@"高雅紫",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 52 | @"theme_background_color":@[@"0x722896",@"0.9"], 53 | @"button_background_color":@[@"0xE8DAEF",@"0.9"], 54 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 55 | @"font-color":@[@"0x2D3F64",@"1.0"], 56 | @"specialButton_bg_color":@[@"0x965CB1",@"0.9"], 57 | }, 58 | 59 | @{ 60 | @"theme_name":@"橙色", 61 | @"theme_icon_image":@"橙色",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 62 | @"theme_background_color":@[@"0xBB571D",@"0.9"], 63 | @"button_background_color":@[@"0xF96E48",@"1.0"], 64 | @"button_Key_color":@[@"0xF84F2B",@"0.9"], 65 | @"font-color":@[@"0xFFF2F0",@"1.0"], 66 | @"specialButton_bg_color":@[@"0xFBA563",@"0.9"], 67 | 68 | }, 69 | @{ 70 | @"theme_name":@"蓝色", 71 | @"theme_icon_image":@"蓝色",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 72 | @"theme_background_color":@[@"0x2A557D",@"0.9"], 73 | @"button_background_color":@[@"0x80AECA",@"0.9"], 74 | @"button_Key_color":@[@"0x3D9BD8",@"0.9"], 75 | @"font-color":@[@"0xE5EFF5",@"1.0"], 76 | @"specialButton_bg_color":@[@"0x6299CC",@"0.9"], 77 | }, 78 | @{ 79 | @"theme_name":@"图片", 80 | @"theme_icon_image":@"44",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 81 | @"theme_background_color":@"44", 82 | @"button_background_color":@[@"0x6D7989",@"0.9"], 83 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 84 | @"font-color":@[@"0xC9CED5",@"1.0"], 85 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], 86 | }, 87 | @{ 88 | @"theme_name":@"图片1", 89 | @"theme_icon_image":@"back_sky_dark",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 90 | @"theme_background_color":@"back_sky_dark", 91 | @"button_background_color":@[@"0x6D7989",@"0.9"], 92 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 93 | @"font-color":@[@"0xC9CED5",@"1.0"], 94 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], 95 | }, 96 | @{ 97 | @"theme_name":@"图片2", 98 | @"theme_icon_image":@"back_sky_yellow",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 99 | @"theme_background_color":@"back_sky_yellow", 100 | @"button_background_color":@[@"0x6D7989",@"0.9"], 101 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 102 | @"font-color":@[@"0xC9CED5",@"1.0"], 103 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], }, 104 | @{ 105 | @"theme_name":@"图片3", 106 | @"theme_icon_image":@"back_ocean",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 107 | @"theme_background_color":@"back_ocean", 108 | @"button_background_color":@[@"0x6D7989",@"0.9"], 109 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 110 | @"font-color":@[@"0xC9CED5",@"1.0"], 111 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], }, 112 | @{ 113 | @"theme_name":@"图片4", 114 | @"theme_icon_image":@"33",//or @"aaa.jpg" //数组则为颜色;字符串则为图片 115 | @"theme_background_color":@"33", 116 | @"button_background_color":@[@"0x6D7989",@"0.9"], 117 | @"button_Key_color":@[@"0xFA890D",@"0.9"], 118 | @"font-color":@[@"0xC9CED5",@"1.0"], 119 | @"specialButton_bg_color":@[@"0x4D5C6F",@"0.9"], 120 | }, 121 | ]; 122 | } 123 | - (void)didReceiveMemoryWarning { 124 | [super didReceiveMemoryWarning]; 125 | } 126 | -(UIView *)makeThemeCell:(NSDictionary *)theme{//绘制主题单元格 127 | UIView *cell=[[[NSBundle mainBundle]loadNibNamed:@"themeCell" owner:self options:nil]lastObject];//@"themeCell"是.xib的名字 128 | UIButton * button=[cell viewWithTag:1000]; 129 | UILabel *themeTitle=[cell viewWithTag:1001]; 130 | UIImageView *selectTheme=[cell viewWithTag:1002]; 131 | [button setBackgroundImage:[UIImage imageNamed:theme[@"theme_icon_image"]] forState:UIControlStateNormal]; 132 | themeTitle.text=theme[@"theme_name"]; 133 | 134 | if ([currentSelcetTheme isEqualToString:theme[@"theme_name"]]) { 135 | selectTheme.hidden=NO; 136 | [themeTitle setTextColor:RGB(0x000000)]; 137 | themeTitle.alpha=0.7; 138 | } 139 | [button addTarget:self action:@selector(themeClick:) forControlEvents:UIControlEventTouchUpInside];//绑定button事件 140 | return cell; 141 | } 142 | -(void)themeClick:(UIButton *)button{ 143 | 144 | int index = (int)button.superview.tag - 5000; 145 | NSDictionary * dict = themeArray[index]; 146 | NSLog(@"%@",dict); 147 | currentSelcetTheme = dict[@"theme_name"]; 148 | 149 | for (UIView * view in self.scrollView.subviews) { 150 | if(view.tag>=5000){ 151 | [view removeFromSuperview]; 152 | } 153 | } 154 | [Common configSet:@"key_setting_theme" value:dict]; 155 | isSateDefine=@"0"; 156 | NSLog(@"isSateDefine%@",isSateDefine); 157 | [Common configSet:@"theme_Define_background" value:isSateDefine]; 158 | 159 | [self loadThemeList]; 160 | } 161 | -(void)loadThemeList{ 162 | int rowHight=0; 163 | int rowNum=0; 164 | for (int i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Calculator1Tests/Calculator1Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Calculator1Tests.m 3 | // Calculator1Tests 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Calculator1Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Calculator1Tests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Calculator1Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Calculator1UITests/Calculator1UITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Calculator1UITests.m 3 | // Calculator1UITests 4 | // 5 | // Created by ruru on 16/4/12. 6 | // Copyright © 2016年 ruru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Calculator1UITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Calculator1UITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Calculator1UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Calculator 2 | 这一款计算器是科学计算器,它不单可以实现简单的加减乘除运算, 3 | 还可进行乘方、开方、指数、对数、三角函数(弧度制和角度值切换)等方面的运算。它还可以存储计算历史记录,并且可以选择并使用历史记录。还可以更换计算器的主题风格。 4 | --------------------------------------------------------------------------------