2025年高频iossql面试题及答案_第1页
2025年高频iossql面试题及答案_第2页
2025年高频iossql面试题及答案_第3页
2025年高频iossql面试题及答案_第4页
2025年高频iossql面试题及答案_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2025年高频iossql面试题及答案iOS开发中SQL相关技能是数据持久化模块的核心能力,以下整理2025年高频面试问题及深度解析:Q1:iOS中使用SQLite时,FMDB与原生sqlite3API各有什么优劣势?实际项目中如何选择?FMDB基于Objective-C封装了sqlite3的C语言接口,优势在于:①简化API,用OC方法替代繁琐的C函数(如executeUpdate替代sqlite3_prepare_v2+sqlite3_step);②自动处理内存管理(如自动释放stmt);③线程安全支持(FMDatabaseQueue通过GCD队列管理多线程操作);④结果集解析方便(FMResultSet封装了字段类型转换)。劣势是增加了一层封装开销,极端性能敏感场景可能不如原生API;部分复杂操作(如自定义busyhandler)需要通过rawSQL实现。原生sqlite3API优势:①零封装开销,适合需要极致性能的场景(如百万级数据批量写入);②完全控制SQL执行流程(如手动管理stmt重用);③支持更底层的配置(如PRAGMA指令的实时调整)。劣势:①代码冗余(需手动处理内存释放、错误码判断);②线程安全需完全手动管理(需结合GCD或NSOperationQueue);③结果集解析需手动处理字段类型(如通过sqlite3_column_text获取字符串)。选择建议:业务型项目优先FMDB(开发效率高,减少错误);工具类/性能敏感型项目(如日志系统)可混合使用(核心写入用原生API,查询用FMDB);需注意FMDB3.0+已支持Swift,Swift项目可选择FMDB或GRDB(另一种Swift友好的封装库)。Q2:CoreData的NSPersistentContainer默认包含哪些组件?如何优化NSFetchRequest的查询性能?NSPersistentContainer整合了CoreData三大核心组件:NSManagedObjectModel:数据模型描述(.xcdatamodeld文件编译后的产物);NSPersistentStoreCoordinator:负责连接存储(默认SQLite),管理模型与存储的映射;NSManagedObjectContext:管理对象的生命周期,处理持久化操作(插入、删除、更新)。NSFetchRequest优化策略:①限制返回字段:使用propertiesToFetch指定仅需要的属性(避免加载全字段),配合resultType=NSDictionaryResultType直接获取字典;②分页查询:设置fetchLimit(每页数量)和fetchOffset(偏移量),避免一次性加载大量数据;③预取关联对象:对关系型数据使用includesSubentities(是否包含子实体)和includesPropertyValues(是否加载属性值),结合fetchBatchSize(批量加载大小)优化关联查询;④索引支持:在模型中为常查询的属性添加索引(模型编辑器中勾选“Indexed”),CoreData会自动在SQLite表中创建索引;⑤使用谓词优化:避免在谓词中使用函数(如SUBSTRING)或计算(如age+1>20),这些会导致全表扫描;优先使用范围查询(BETWEEN)或等式查询;⑥禁用自动更新:对只读查询设置includesPendingChanges=NO,避免上下文中未提交的变更影响结果;⑦分析执行计划:通过context.persistentStoreCoordinator?.managedObjectIDForURIRepresentation(...)获取底层SQL,结合sqlite3_analyzer工具分析查询效率。Q3:如何处理iOS多线程环境下的数据库并发问题?FMDB和CoreData的解决方案有何不同?多线程并发的核心问题是SQLite的写锁机制(同一时间仅允许一个写操作),处理不当会导致SQLITE_BUSY错误或数据损坏。FMDB方案:禁止多线程共享FMDatabase实例(其非线程安全);使用FMDatabaseQueue管理队列,所有数据库操作通过queueinDatabase:或inTransaction:提交到串行队列,确保操作顺序执行;对于读多写少场景,可配合FMDatabase的readOnly属性创建只读实例(共享读锁),但需注意写操作仍需通过队列。CoreData方案:上下文(NSManagedObjectContext)的线程亲和性:每个线程使用独立上下文(根据concurrencyType设置:mainQueue/privateQueue);主从上下文模式:主线程使用mainQueueConcurrencyType上下文,后台线程使用privateQueueConcurrencyType上下文,通过parentContext建立父子关系,后台上下文保存(save:)后,主上下文通过mergeChangesFromContextDidSaveNotification合并变更;避免跨线程传递NSManagedObject实例(其非线程安全),需通过objectID(可跨线程)重新获取实例;高级场景可使用NSPersistentStoreCoordinator的performBlock:方法直接操作存储层,但需谨慎处理锁。关键差异:FMDB通过GCD队列实现操作序列化,CoreData通过上下文的线程隔离+变更合并实现并发安全,后者更适合复杂对象图的多线程操作。Q4:SQLite的事务机制如何提升写入性能?实际使用中需要注意哪些问题?SQLite默认是自动提交模式(每个INSERT/UPDATE/DELETE语句自动开启并提交事务),频繁单条写入会导致大量磁盘IO(每次提交需写入WAL日志并同步)。开启显式事务后,多条操作在一个事务中执行,仅最后提交时同步磁盘,显著减少IO次数。测试显示,百万条数据插入时,事务模式比非事务模式快约100倍。注意事项:①事务范围控制:避免事务过大(如包含上万条操作),长时间持有写锁可能导致其他线程阻塞(触发SQLITE_BUSY);②异常处理:事务中若发生错误(如约束冲突),必须回滚(rollback)而非直接终止,否则数据库可能进入“事务挂起”状态,后续操作失败;③嵌套事务:SQLite不支持真正的嵌套事务,多次BEGIN会被视为单层事务,COMMIT仅提交最外层;④WAL模式影响:启用WAL(PRAGMAjournal_mode=WAL)后,事务提交更快(无需同步主数据库文件),但需注意WAL文件的自动清理(通过PRAGMAwal_checkpoint);⑤CoreData中的事务:CoreData的save:方法默认以事务方式提交,多次对同一上下文调用insert/delete后统一save可自动利用事务。Q5:如何防范iOS中SQLite的SQL注入攻击?实际开发中容易踩的坑有哪些?SQL注入的本质是将用户输入的数据当作SQL代码执行,防范核心是使用参数化查询(预编译语句),而非字符串拼接。正确做法:原生API:使用sqlite3_prepare_v2编译带?占位符的SQL语句,通过sqlite3_bind_系列函数绑定参数(如sqlite3_bind_text(stmt,1,username.UTF8String,-1,SQLITE_TRANSIENT));FMDB:使用executeUpdate:@"INSERTINTOuser(name)VALUES(?)",username;或带字典的executeUpdate:withParameterDictionary:方法;CoreData:谓词(NSPredicate)自动使用参数化查询(如[NSPredicatepredicateWithFormat:@"name=%@",username]),底层会转换为参数绑定。常见误区:①认为“数据来自内部就安全”:即使数据来自应用内部(如用户输入的备注字段),仍可能包含特殊字符(如单引号)导致SQL语法错误或注入;②手动转义引号:如将单引号替换为两个单引号('→''),但这种方法易遗漏其他特殊字符(如分号;),且不同数据库转义规则不同,参数化查询是更可靠的方案;③错误使用字符串拼接:例如[NSStringstringWithFormat:@"SELECTFROMuserWHEREname='%@'",username],这种写法在username包含'时会破坏SQL结构(如输入O'Neil会变成WHEREname='O'Neil',导致语法错误或注入);④动态表名/字段名:参数化查询不支持表名或字段名作为参数(因为预编译阶段需确定表结构),此时需手动校验白名单(如仅允许已知的表名),禁止直接使用用户输入。Q6:iOS数据库迁移(Schema变更)的常见场景有哪些?如何实现轻量级迁移和手动迁移?常见迁移场景:添加字段(如用户表新增“avatarUrl”字段);删除字段(如废弃“oldPhone”字段);修改字段类型(如“age”从INTEGER改为TEXT);重命名字段/表;新增关联关系(如用户与订单的一对多关系)。轻量级迁移(自动迁移):适用于简单变更,CoreData可自动提供映射模型。需满足以下条件:新增字段(可为NULL或有默认值);删除字段(非必填字段);重命名字段(通过模型的renamingIdentifier属性标记旧名称);变更字段类型(需兼容,如INTEGER→REAL)。实现步骤:1.在Xcode中修改数据模型(.xcdatamodeld),并创建新版本(Editor→AddModelVersion);2.设置当前版本(选中模型文件→右侧属性面板→CurrentVersion);3.配置持久化存储选项:```objcNSPersistentStoreDescriptiondesc=[NSPersistentStoreDescriptionnew];desc.shouldMigrateStoreAutomatically=YES;//自动迁移desc.shouldInferMappingModelAutomatically=YES;//自动推断映射模型```手动迁移:复杂变更(如跨多个版本迁移、字段逻辑转换)需自定义映射模型(NSEntityMapping)和迁移策略(NSEntityMigrationPolicy)。步骤:1.创建旧模型(v1)和新模型(v2);2.新建映射模型(.xcmappingmodel),配置实体映射关系;3.自定义迁移策略类(继承NSEntityMigrationPolicy),重写关键方法(如createDestinationInstancesForSourceInstance:entityMapping:manager:error:)处理数据转换;4.加载自定义映射模型,替换自动迁移:```objcNSURLmappingURL=[[NSBundlemainBundle]URLForResource:@"V1ToV2"withExtension:@"xcmappingmodel"];NSMappingModelmapping=[NSMappingModelmappingModelFromBundles:@[[NSBundlemainBundle]]forSourceModel:sourceModeldestinationModel:destModel];NSErrorerror;BOOLsuccess=[coordinatormigratePersistentStore:storefromURL:storeURLoptions:@{NSMigratePersistentStoresAutomaticallyOption:@NO}withMappingModel:mappingtoURL:newStoreURLstoreType:NSSQLiteStoreTypeerror:&error];```注意:迁移前需备份原数据库(通过复制文件),迁移过程中避免用户操作(可显示加载界面),并在测试时覆盖所有版本升级路径(如v1→v3需测试v1→v2→v3和v1→v3直接迁移)。Q7:如何优化SQLite数据库的存储空间?大字段(如图像、视频)应该存储在数据库还是文件系统?存储空间优化策略:①字段类型优化:使用最小必要类型(如TINYINT替代INTEGER存储布尔值),避免TEXT存储数字(增加索引开销);②启用压缩:集成SQLCipher时可开启压缩(需SQLite编译时启用ZLIB支持),或对BLOB字段手动压缩(如用NSData的gzip压缩);③清理冗余数据:定期删除过期缓存(如设置maxAge=7天),使用DELETE+VACUUM命令回收空间(VACUUM会重建数据库文件,可能耗时);④避免NULL字段:SQLite对NULL字段仍有存储开销(1字节),可为字段设置默认值(如DEFAULT'')避免NULL;⑤使用WAL模式:WAL文件比传统回滚日志更紧凑,且自动截断旧日志。大字段存储决策:小于100KB的二进制数据(如小图标、JSON配置):可存储为BLOB字段,优势是原子性(随事务提交)、查询方便(可直接关联其他字段);大于100KB的数据(如高清图片、视频):建议存储在文件系统,数据库仅记录文件路径(TEXT类型)。原因:→SQLite对大BLOB的读写性能较差(需加载整个BLOB到内存);→文件系统对大文件的分块读写更高效(可部分读取);→避免数据库文件过大(单文件过大影响备份、恢复和IO性能);→便于利用系统级缓存(如iOS的文件缓存机制)。混合方案:对需要快速访问的小缩略图存BLOB,原图存文件;或使用“懒加载”策略,首次访问大文件时从数据库读取并保存到文件系统,后续从文件读取。Q8:CoreData的NSFetchedResultsController在UITableView中的使用注意事项有哪些?如何处理数据变更的实时刷新?NSFetchedResultsController(FRC)是专为UITableView/UICollectionView设计的控制器,通过监听CoreData上下文的变更自动更新数据源。注意事项:①初始化配置:需指定正确的managedObjectContext(与tableView同线程)、fetchRequest(需设置sectionNameKeyPath或cacheName);②缓存使用:设置cacheName可缓存查询结果,提升滚动性能,但需注意缓存失效(模型变更或数据大量修改时需删除旧缓存);③线程安全:FRC的delegate方法(如controller:didChangeObject:)默认在上下文所在线程执行(如mainQueue),需确保UI更新在主线程;④批量操作优化:对大量数据变更(如删除100条记录),应暂时移除delegate,批量保存后再添加,避免频繁调用tableView的insert/delete方法导致卡顿;⑤处理重复数据:fetchRequest需设置sortDescriptors(否则FRC无法正确跟踪顺序),且需确保数据唯一性(避免同一对象多次触发变更通知)。实时刷新实现:注册上下文保存通知:FRC内部已监听NSManagedObjectContextDidSaveNotification,变更会自动同步到UI;手动刷新:若上下文未自动合并变更(如跨上下文操作),需调用[controllerperformFetch:&error]手动刷新;处理冲突:若多个上下文同时修改同一对象,需在保存时处理合并冲突(通过mergePolicy属性,默认NSMergeByPropertyStoreTrumpMergePolicy)。Q9:SQLite的索引设计原则有哪些?哪些场景不适合创建索引?索引设计原则:①针对高频查询字段:为WHERE子句、JOIN条件、ORDERBY/GROUPBY中的字段创建索引;②最左匹配原则:复合索引(如(name,age))可加速name查询、name+age查询,但无法加速age单独查询;③避免冗余索引:如已有(name,age)索引,无需再创建name单独索引(除非name查询极高频且age字段很大);④索引字段长度:对长文本字段(如content)使用前缀索引(CREATEINDEXidx_contentONtable(content(20))),减少索引大小;⑤覆盖索引:若查询仅需要索引中的字段(如SELECTnameFROMuserWHEREage=20),可创建(age,name)索引,避免回表查询。不适合索引的场景:①低基数字段:如性别(仅男/女),索引无法有效过滤数据;②频繁更新的字段:索引会增加INSERT/UPDATE/DELETE的开销(每次变更需更新索引);③小表:数据量小于1000条时,全表扫描可能比索引查询更快;④大字段:如TEXT/BLOB类型,索引存储和维护成本高;⑤仅查询一次的字段:临时查询无需长期维护索引。Q10:iOS中如何实现数据库加密?SQLCipher集成的关键步骤和注意事项有哪些?数据库加密的核心是对存储的二进制数据加密,防止直接通过文件读取获取明文。iOS常用方案是集成SQLCipher(基于SQLite的加密扩展)。集成步骤:1.通过Coco

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论