文章的目的为了记录使用Objective-C 进行IOS app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 Objective-C IOS 应用开发(一)macOS 的使用
开源 Objective-C IOS 应用开发(二)Xcode安装
开源 Objective-C IOS 应用开发(三)第一个iPhone的APP
开源 Objective-C IOS 应用开发(四)Xcode工程文件结构
开源 Objective-C IOS 应用开发(五)iOS操作(action)和输出口(Outlet)
开源 Objective-C IOS 应用开发(六)Objective-C 和 C语言
开源 Objective-C IOS 应用开发(七)Objective-C核心代码示例
开源 Objective-C IOS 应用开发(八)常见控件UI
开源 Objective-C IOS 应用开发(九)复杂控件-tableview
开源 Objective-C IOS 应用开发(十)数据持久化--文件
开源 Objective-C IOS 应用开发(十一)数据持久化--sqlite
开源 Objective-C IOS 应用开发(十二)通讯--ble
开源 Objective-C IOS 应用开发(十三)通讯--Http访问
开源 Objective-C IOS 应用开发(十四)传感器--陀螺仪和gps
开源 Objective-C IOS 应用开发(十五)通讯--蓝牙ble扫描
开源 Objective-C IOS 应用开发(十六)Storyboard模式下的纯代码界面
开源 Objective-C IOS 应用开发(十七)CAF音频的录制
开源 Objective-C IOS 应用开发(十八)音频的播放
开源 Objective-C IOS 应用开发(十九)视频的播放
开源 Objective-C IOS 应用开发(二十)多线程处理
开源 Objective-C IOS 应用开发(二十一)自定义控件--示波器
开源 Objective-C IOS 应用开发(二十二)自定义控件--车速仪表盘
推荐链接:
开源 Arkts 鸿蒙应用 开发(一)工程文件分析-优快云博客
开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-优快云博客
开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-优快云博客
开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-优快云博客
开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-优快云博客
开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储-优快云博客
开源 Arkts 鸿蒙应用 开发(七)数据持久--sqlite关系数据库-优快云博客
开源 Arkts 鸿蒙应用 开发(八)多媒体--相册和相机-优快云博客
开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端-优快云博客
开源 Arkts 鸿蒙应用 开发(十)通讯--Http-优快云博客
开源 Arkts 鸿蒙应用 开发(十一)证书和包名修改-优快云博客
开源 Arkts 鸿蒙应用 开发(十二)传感器的使用-优快云博客
开源 Arkts 鸿蒙应用 开发(十三)音频--MP3播放_arkts avplayer播放音频 mp3-优快云博客
开源 Arkts 鸿蒙应用 开发(十四)线程--任务池(taskpool)-优快云博客
开源 Arkts 鸿蒙应用 开发(十五)自定义绘图控件--仪表盘-优快云博客
开源 Arkts 鸿蒙应用 开发(十六)自定义绘图控件--波形图-优快云博客
开源 Arkts 鸿蒙应用 开发(十七)通讯--http多文件下载-优快云博客
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器-优快云博客
推荐链接:
开源 java android app 开发(一)开发环境的搭建-优快云博客
开源 java android app 开发(二)工程文件结构-优快云博客
开源 java android app 开发(三)GUI界面布局和常用组件-优快云博客
开源 java android app 开发(四)GUI界面重要组件-优快云博客
开源 java android app 开发(五)文件和数据库存储-优快云博客
开源 java android app 开发(六)多媒体使用-优快云博客
开源 java android app 开发(七)通讯之Tcp和Http-优快云博客
开源 java android app 开发(八)通讯之Mqtt和Ble-优快云博客
开源 java android app 开发(九)后台之线程和服务-优快云博客
开源 java android app 开发(十)广播机制-优快云博客
开源 java android app 开发(十一)调试、发布-优快云博客
开源 java android app 开发(十二)封库.aar-优快云博客
本章内容主要是完整的 iOS 客户管理应用,使用 SQLite 数据库进行数据存储。
目录:
1.手机演示
2.所有源码
3.源码分析
一、手机演示

二、所有源码
需添加修改这4个文件

1. 数据库管理类 (DatabaseManager.h)
#import <Foundation/Foundation.h>
#import <sqlite3.h>
NS_ASSUME_NONNULL_BEGIN
@interface Customer : NSObject
@property (nonatomic, assign) NSInteger customerId;
@property (nonatomic, copy) NSString *customerName;
@property (nonatomic, copy) NSString *contactPerson;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSString *phone;
@end
@interface DatabaseManager : NSObject
+ (instancetype)sharedInstance;
- (BOOL)openDatabase;
- (BOOL)createTable;
- (BOOL)addCustomerWithName:(NSString *)name contactPerson:(NSString *)contact address:(NSString *)address phone:(NSString *)phone;
- (BOOL)updateCustomer:(Customer *)customer;
- (BOOL)deleteCustomerWithId:(NSInteger)customerId;
- (NSArray<Customer *> *)getAllCustomers;
- (NSArray<Customer *> *)searchCustomersWithKeyword:(NSString *)keyword;
@end
NS_ASSUME_NONNULL_END
2. 数据库管理类实现 (DatabaseManager.m)
#import "DatabaseManager.h"
@implementation Customer
@end
@interface DatabaseManager()
@property (nonatomic, assign) sqlite3 *database;
@property (nonatomic, copy) NSString *databasePath;
@end
@implementation DatabaseManager
+ (instancetype)sharedInstance {
static DatabaseManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
if (self = [super init]) {
[self setupDatabasePath];
}
return self;
}
- (void)setupDatabasePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
self.databasePath = [documentsDirectory stringByAppendingPathComponent:@"customers.db"];
}
- (BOOL)openDatabase {
if (sqlite3_open([self.databasePath UTF8String], &_database) == SQLITE_OK) {
return [self createTable];
}
return NO;
}
- (BOOL)createTable {
NSString *createTableSQL = @"CREATE TABLE IF NOT EXISTS Customers ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"customer_name TEXT NOT NULL, "
"contact_person TEXT, "
"address TEXT, "
"phone TEXT);";
char *errorMessage;
if (sqlite3_exec(self.database, [createTableSQL UTF8String], NULL, NULL, &errorMessage) == SQLITE_OK) {
return YES;
} else {
NSLog(@"创建表失败: %s", errorMessage);
sqlite3_free(errorMessage);
return NO;
}
}
- (BOOL)addCustomerWithName:(NSString *)name contactPerson:(NSString *)contact address:(NSString *)address phone:(NSString *)phone {
NSString *insertSQL = @"INSERT INTO Customers (customer_name, contact_person, address, phone) VALUES (?, ?, ?, ?);";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self.database, [insertSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [contact UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [address UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [phone UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE) {
sqlite3_finalize(statement);
return YES;
}
}
sqlite3_finalize(statement);
return NO;
}
- (BOOL)updateCustomer:(Customer *)customer {
NSString *updateSQL = @"UPDATE Customers SET customer_name = ?, contact_person = ?, address = ?, phone = ? WHERE id = ?;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self.database, [updateSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_text(statement, 1, [customer.customerName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [customer.contactPerson UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [customer.address UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [customer.phone UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 5, (int)customer.customerId);
if (sqlite3_step(statement) == SQLITE_DONE) {
sqlite3_finalize(statement);
return YES;
}
}
sqlite3_finalize(statement);
return NO;
}
- (BOOL)deleteCustomerWithId:(NSInteger)customerId {
NSString *deleteSQL = @"DELETE FROM Customers WHERE id = ?;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self.database, [deleteSQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_int(statement, 1, (int)customerId);
if (sqlite3_step(statement) == SQLITE_DONE) {
sqlite3_finalize(statement);
return YES;
}
}
sqlite3_finalize(statement);
return NO;
}
- (NSArray<Customer *> *)getAllCustomers {
NSMutableArray *customers = [NSMutableArray array];
NSString *querySQL = @"SELECT * FROM Customers ORDER BY id;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self.database, [querySQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
Customer *customer = [[Customer alloc] init];
customer.customerId = sqlite3_column_int(statement, 0);
customer.customerName = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
customer.contactPerson = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 2)];
customer.address = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
customer.phone = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 4)];
[customers addObject:customer];
}
}
sqlite3_finalize(statement);
return [customers copy];
}
- (NSArray<Customer *> *)searchCustomersWithKeyword:(NSString *)keyword {
NSMutableArray *customers = [NSMutableArray array];
NSString *querySQL = @"SELECT * FROM Customers WHERE customer_name LIKE ? OR contact_person LIKE ? OR address LIKE ? OR phone LIKE ? ORDER BY id;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self.database, [querySQL UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSString *searchPattern = [NSString stringWithFormat:@"%%%@%%", keyword];
sqlite3_bind_text(statement, 1, [searchPattern UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [searchPattern UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [searchPattern UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [searchPattern UTF8String], -1, SQLITE_TRANSIENT);
while (sqlite3_step(statement) == SQLITE_ROW) {
Customer *customer = [[Customer alloc] init];
customer.customerId = sqlite3_column_int(statement, 0);
customer.customerName = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
customer.contactPerson = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 2)];
customer.address = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
customer.phone = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 4)];
[customers addObject:customer];
}
}
sqlite3_finalize(statement);
return [customers copy];
}
- (void)dealloc {
if (self.database) {
sqlite3_close(self.database);
}
}
@end
3. 主视图控制器 (ViewController.h)
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
@end
4. 主视图控制器实现 (ViewController.m)
#import "ViewController.h"
#import "DatabaseManager.h"
@interface ViewController ()
{
NSArray<Customer *> *_customers;
Customer *_selectedCustomer;
}
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UITextField *nameTextField;
@property (nonatomic, strong) UITextField *contactTextField;
@property (nonatomic, strong) UITextField *addressTextField;
@property (nonatomic, strong) UITextField *phoneTextField;
@property (nonatomic, strong) UITextField *searchTextField;
@property (nonatomic, strong) UIButton *addButton;
@property (nonatomic, strong) UIButton *updateButton;
@property (nonatomic, strong) UIButton *deleteButton;
@property (nonatomic, strong) UIButton *searchButton;
@property (nonatomic, strong) UIButton *clearButton;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupDatabase];
[self setupUI];
[self loadData];
}
- (void)setupDatabase {
DatabaseManager *dbManager = [DatabaseManager sharedInstance];
if (![dbManager openDatabase]) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"错误"
message:@"数据库初始化失败"
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
}
- (void)setupUI {
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"客户管理";
// 创建输入框
[self createTextFields];
// 创建按钮
[self createButtons];
// 创建表格
[self createTableView];
// 布局
[self setupLayout];
}
- (void)createTextFields {
// 搜索框
_searchTextField = [[UITextField alloc] init];
_searchTextField.placeholder = @"搜索客户名、联系人、地址、电话";
_searchTextField.borderStyle = UITextBorderStyleRoundedRect;
_searchTextField.delegate = self;
_searchTextField.returnKeyType = UIReturnKeySearch;
[self.view addSubview:_searchTextField];
// 客户名
_nameTextField = [[UITextField alloc] init];
_nameTextField.placeholder = @"客户名";
_nameTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:_nameTextField];
// 联系人
_contactTextField = [[UITextField alloc] init];
_contactTextField.placeholder = @"联系人";
_contactTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:_contactTextField];
// 地址
_addressTextField = [[UITextField alloc] init];
_addressTextField.placeholder = @"地址";
_addressTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:_addressTextField];
// 电话
_phoneTextField = [[UITextField alloc] init];
_phoneTextField.placeholder = @"电话";
_phoneTextField.borderStyle = UITextBorderStyleRoundedRect;
_phoneTextField.keyboardType = UIKeyboardTypePhonePad;
[self.view addSubview:_phoneTextField];
}
- (void)createButtons {
_addButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_addButton setTitle:@"添加" forState:UIControlStateNormal];
[_addButton addTarget:self action:@selector(addButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_addButton];
_updateButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_updateButton setTitle:@"修改" forState:UIControlStateNormal];
[_updateButton addTarget:self action:@selector(updateButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_updateButton];
_deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_deleteButton setTitle:@"删除" forState:UIControlStateNormal];
[_deleteButton addTarget:self action:@selector(deleteButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_deleteButton];
_searchButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_searchButton setTitle:@"查询" forState:UIControlStateNormal];
[_searchButton addTarget:self action:@selector(searchButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_searchButton];
_clearButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_clearButton setTitle:@"清空" forState:UIControlStateNormal];
[_clearButton addTarget:self action:@selector(clearButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_clearButton];
}
- (void)createTableView {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.tableFooterView = [[UIView alloc] init];
[self.view addSubview:_tableView];
}
- (void)setupLayout {
CGFloat padding = 10;
CGFloat fieldHeight = 40;
CGFloat buttonHeight = 44;
CGFloat screenWidth = self.view.bounds.size.width;
// 搜索框
_searchTextField.frame = CGRectMake(padding, 100, screenWidth - 2 * padding, fieldHeight);
// 按钮行1
CGFloat buttonWidth = (screenWidth - 3 * padding) / 2;
_searchButton.frame = CGRectMake(padding, 150, buttonWidth, buttonHeight);
_clearButton.frame = CGRectMake(padding * 2 + buttonWidth, 150, buttonWidth, buttonHeight);
// 输入框
_nameTextField.frame = CGRectMake(padding, 210, screenWidth - 2 * padding, fieldHeight);
_contactTextField.frame = CGRectMake(padding, 260, screenWidth - 2 * padding, fieldHeight);
_addressTextField.frame = CGRectMake(padding, 310, screenWidth - 2 * padding, fieldHeight);
_phoneTextField.frame = CGRectMake(padding, 360, screenWidth - 2 * padding, fieldHeight);
// 按钮行2
_addButton.frame = CGRectMake(padding, 420, buttonWidth, buttonHeight);
_updateButton.frame = CGRectMake(padding * 2 + buttonWidth, 420, buttonWidth, buttonHeight);
_deleteButton.frame = CGRectMake(padding, 480, screenWidth - 2 * padding, buttonHeight);
// 表格
CGFloat tableY = 540;
_tableView.frame = CGRectMake(0, tableY, screenWidth, self.view.bounds.size.height - tableY);
}
- (void)loadData {
_customers = [[DatabaseManager sharedInstance] getAllCustomers];
[self.tableView reloadData];
}
- (void)clearInputFields {
_nameTextField.text = @"";
_contactTextField.text = @"";
_addressTextField.text = @"";
_phoneTextField.text = @"";
_selectedCustomer = nil;
}
#pragma mark - Button Actions
- (void)addButtonTapped {
if (_nameTextField.text.length == 0) {
[self showAlertWithTitle:@"提示" message:@"请输入客户名"];
return;
}
DatabaseManager *dbManager = [DatabaseManager sharedInstance];
BOOL success = [dbManager addCustomerWithName:_nameTextField.text
contactPerson:_contactTextField.text
address:_addressTextField.text
phone:_phoneTextField.text];
if (success) {
[self showAlertWithTitle:@"成功" message:@"客户添加成功"];
[self clearInputFields];
[self loadData];
} else {
[self showAlertWithTitle:@"错误" message:@"添加客户失败"];
}
}
- (void)updateButtonTapped {
if (!_selectedCustomer) {
[self showAlertWithTitle:@"提示" message:@"请先选择要修改的客户"];
return;
}
if (_nameTextField.text.length == 0) {
[self showAlertWithTitle:@"提示" message:@"请输入客户名"];
return;
}
Customer *customer = [[Customer alloc] init];
customer.customerId = _selectedCustomer.customerId;
customer.customerName = _nameTextField.text;
customer.contactPerson = _contactTextField.text;
customer.address = _addressTextField.text;
customer.phone = _phoneTextField.text;
DatabaseManager *dbManager = [DatabaseManager sharedInstance];
BOOL success = [dbManager updateCustomer:customer];
if (success) {
[self showAlertWithTitle:@"成功" message:@"客户修改成功"];
[self clearInputFields];
[self loadData];
} else {
[self showAlertWithTitle:@"错误" message:@"修改客户失败"];
}
}
- (void)deleteButtonTapped {
if (!_selectedCustomer) {
[self showAlertWithTitle:@"提示" message:@"请先选择要删除的客户"];
return;
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"确认删除"
message:@"确定要删除这个客户吗?"
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:@"删除" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
DatabaseManager *dbManager = [DatabaseManager sharedInstance];
BOOL success = [dbManager deleteCustomerWithId:self->_selectedCustomer.customerId];
if (success) {
[self showAlertWithTitle:@"成功" message:@"客户删除成功"];
[self clearInputFields];
[self loadData];
} else {
[self showAlertWithTitle:@"错误" message:@"删除客户失败"];
}
}]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)searchButtonTapped {
if (_searchTextField.text.length == 0) {
[self loadData]; // 如果搜索框为空,显示所有数据
return;
}
_customers = [[DatabaseManager sharedInstance] searchCustomersWithKeyword:_searchTextField.text];
[self.tableView reloadData];
[self.view endEditing:YES];
}
- (void)clearButtonTapped {
_searchTextField.text = @"";
[self loadData];
}
#pragma mark - UITableView DataSource & Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _customers.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"CustomerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
Customer *customer = _customers[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@ - %@", customer.customerName, customer.contactPerson];
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ | %@", customer.address, customer.phone];
cell.detailTextLabel.numberOfLines = 2;
// 标记选中的行
if (_selectedCustomer && _selectedCustomer.customerId == customer.customerId) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:1.0 alpha:1.0];
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
cell.backgroundColor = [UIColor whiteColor];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
_selectedCustomer = _customers[indexPath.row];
// 填充数据到输入框
_nameTextField.text = _selectedCustomer.customerName;
_contactTextField.text = _selectedCustomer.contactPerson;
_addressTextField.text = _selectedCustomer.address;
_phoneTextField.text = _selectedCustomer.phone;
[tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 70;
}
#pragma mark - UITextField Delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == _searchTextField) {
[self searchButtonTapped];
return YES;
}
return NO;
}
#pragma mark - Helper Methods
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
@end
三、源码分析
1. 数据库管理类 (DatabaseManager)
1.1 数据模型 (Customer)
objc
@interface Customer : NSObject
@property (nonatomic, assign) NSInteger customerId;
@property (nonatomic, copy) NSString *customerName;
@property (nonatomic, copy) NSString *contactPerson;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSString *phone;
@end
-
使用
copy属性确保字符串不可变 -
customerId作为主键,对应数据库中的自增 ID
1.2 单例模式实现
objc
+ (instancetype)sharedInstance {
static DatabaseManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
-
使用
dispatch_once确保线程安全的单例 -
整个应用共享同一个数据库实例
1.3 数据库路径设置
objc
- (void)setupDatabasePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
self.databasePath = [documentsDirectory stringByAppendingPathComponent:@"customers.db"];
}
-
数据库文件保存在 Documents 目录,确保数据持久化且可备份
-
文件名为
customers.db
1.4 数据库表结构
sql
CREATE TABLE IF NOT EXISTS Customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_name TEXT NOT NULL,
contact_person TEXT,
address TEXT,
phone TEXT
);
-
使用
IF NOT EXISTS避免重复创建 -
id作为自增主键 -
customer_name为必填字段
1.5 CRUD 操作实现
添加客户:使用参数化查询防止 SQL 注入
objc
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
查询操作:使用 sqlite3_step 遍历结果集
objc
while (sqlite3_step(statement) == SQLITE_ROW) {
// 处理每一行数据
}
搜索功能:使用 LIKE 模糊查询
objc
NSString *searchPattern = [NSString stringWithFormat:@"%%%@%%", keyword];
2. 界面控制器 (ViewController)
2.1 UI 组件
-
输入框:客户名、联系人、地址、电话、搜索框
-
功能按钮:添加、修改、删除、查询、清空
-
表格视图:显示客户列表
2.2 核心功能实现
数据加载:
objc
- (void)loadData {
_customers = [[DatabaseManager sharedInstance] getAllCustomers];
[self.tableView reloadData];
}
添加客户:
-
验证客户名不能为空
-
调用数据库管理器的添加方法
-
成功后清空输入框并刷新列表
修改客户:
-
需要先选择客户(设置
_selectedCustomer) -
使用选中客户的 ID 进行更新
删除客户:
-
添加确认对话框,防止误操作
-
使用 UIAlertController 提供取消选项
搜索功能:
-
支持多字段模糊搜索
-
空搜索时显示所有数据
2.3 表格交互
objc
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
_selectedCustomer = _customers[indexPath.row];
// 填充数据到输入框
_nameTextField.text = _selectedCustomer.customerName;
// ... 其他字段
}
-
点击行时选中客户并填充表单
-
使用 accessoryType 和背景色显示选中状态
1456

被折叠的 条评论
为什么被折叠?



