一、内存泄露排查:循环引用检测与修复
内存泄露的本质是对象不再被需要,但引用计数无法归零,导致内存无法释放。
🔧 核心排查工具
- Xcode Memory Graph Debugger:运行时可视化对象引用关系,紫色
!图标标识潜在泄露 - Instruments Leaks工具:实时监控泄露对象,定位未释放的CF对象
- 静态代码分析:检查闭包、代理、通知等常见泄露场景
💡 高频泄露场景与修复
// 1. 闭包循环引用(常见于网络回调)
class TransactionManager {
var completion: ((Bool) -> Void)?
func processTransaction(amount: Double) {
// ❌ 错误:闭包强持有self
APIClient.sendTransaction(amount: amount) { success in
self.updateUI() // 形成循环引用
}
// ✅ 正确:使用weak打破循环
APIClient.sendTransaction(amount: amount) { [weak self] success in
self?.updateUI()
}
}
}
// 2. 代理强引用
class AccountViewController {
// ❌ 错误:强引用代理
var delegate: AccountDelegate?
// ✅ 正确:弱引用代理
weak var delegate: AccountDelegate?
}
// 3. 定时器未正确销毁
class TimerHandler {
var timer: Timer?
deinit {
// ✅ 必须手动invalidate
timer?.invalidate()
timer = nil
}
}
二、网络数据加密:金融级安全传输方案
APP对数据传输安全有极高要求需要多层加密保护。
🔐 多层次加密架构
graph TD
A[客户端请求] --> B[应用层加密]
B --> C[传输层加密 HTTPS]
C --> D[服务端接收]
subgraph "应用层加密细节"
B1[敏感参数单独加密] --> B2[参数排序与签名]
B2 --> B3[加入时间戳/随机数]
end
🛡️ 核心加密实践
1. 传输层安全(基础)
// ATS强制HTTPS(Info.plist配置)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/> <!-- 生产环境必须为false -->
</dict>
// SSL Pinning防中间人攻击
let session = URLSession(configuration: .default,
delegate: SSLPinningDelegate(),
delegateQueue: nil)
2. 应用层加密(增强)
// 敏感数据RSA加密示例
func encryptSensitiveData(_ data: String) -> String? {
// 1. 从服务端获取RSA公钥(首次启动或定期更新)
guard let publicKey = KeychainManager.getRSAPublicKey() else {
return nil
}
// 2. 加密密码、验证码等敏感字段
let encryptedPassword = RSA.encrypt(data, publicKey: publicKey)
// 3. 生成请求签名
let timestamp = Int(Date().timeIntervalSince1970)
let nonce = UUID().uuidString
let signString = "\(data)\(timestamp)\(nonce)\(API_SECRET)"
let signature = HMAC.sha256(signString)
return encryptedPassword
}
// 请求参数签名示例
struct SecureRequest {
let userId: String
let encryptedData: String
let timestamp: Int
let nonce: String
let signature: String
init(userId: String, sensitiveData: String) {
self.userId = userId
self.timestamp = Int(Date().timeIntervalSince1970)
self.nonce = UUID().uuidString
// 加密敏感数据
self.encryptedData = RSA.encrypt(sensitiveData)
// 生成签名(防篡改)
let params = "userId=\(userId)&data=\(encryptedData)×tamp=\(timestamp)&nonce=\(nonce)"
self.signature = HMAC.sha256(params + API_SECRET)
}
}
3. 密钥安全管理
- 禁止硬编码:绝不将密钥直接写在代码中
- Keychain存储:使用iOS Keychain存储加密密钥
- 动态获取:敏感密钥从服务端动态获取,可定期轮换
📊 加密方案选择指南
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 登录密码/支付密码 | RSA非对称加密 | 公钥加密,私钥解密,避免密钥传输 |
| 交易数据/个人信息 | AES对称加密 | 性能好,适合大量数据加密 |
| 请求防篡改 | HMAC-SHA256签名 | 验证数据完整性 |
| 防重放攻击 | 时间戳+随机数 | 确保请求唯一性 |
三、通用缓存:性能优化与数据管理
缓存设计需平衡速度、空间和一致性,金融APP尤其需注意数据实时性和安全性。
🗂️ 三级缓存架构
// 1. 内存缓存(NSCache - 自动清理)
class MemoryCache {
static let shared = MemoryCache()
private let cache = NSCache<NSString, AnyObject>()
private init() {
cache.countLimit = 100 // 限制缓存数量
cache.totalCostLimit = 50 * 1024 * 1024 // 50MB内存限制
}
func cacheTransaction(_ transaction: Transaction, for key: String) {
cache.setObject(transaction, forKey: key as NSString)
}
}
// 2. 磁盘缓存(FileManager - 持久化)
class DiskCache {
func cacheData(_ data: Data, for key: String, expiration: TimeInterval = 3600) {
let fileURL = cacheDirectory.appendingPathComponent(key.md5)
// 存储缓存元数据(包含过期时间)
let metadata = CacheMetadata(expiration: Date().addingTimeInterval(expiration))
let metadataData = try? JSONEncoder().encode(metadata)
// 写入文件
try? data.write(to: fileURL)
try? metadataData?.write(to: metadataURL(for: key))
}
}
// 3. 数据库缓存(Core Data - 结构化数据)
class DatabaseCache {
func cacheUserTransactions(_ transactions: [Transaction]) {
let context = persistentContainer.viewContext
// 批量插入/更新
transactions.forEach { transaction in
let cdTransaction = CDTransaction(context: context)
cdTransaction.id = transaction.id
cdTransaction.amount = transaction.amount
cdTransaction.timestamp = transaction.date
}
try? context.save()
}
}
⚙️ 缓存策略实现
1. 缓存键设计
struct CacheKey {
// 复合键:类型 + 业务ID + 版本号
static func forTransactionList(userId: String, page: Int, pageSize: Int) -> String {
return "transaction_list_\(userId)_\(page)_\(pageSize)_v2"
}
// 带版本的键:数据结构变更时自动失效旧缓存
static func forUserProfile(userId: String) -> String {
return "user_profile_\(userId)_v3" // 版本号递增
}
}
2. 缓存清理策略
// LRU(最近最少使用)清理
class LRUCacheManager {
private var accessHistory: [String: Date] = [:]
func cleanupIfNeeded() {
let now = Date()
let expirationInterval: TimeInterval = 7 * 24 * 3600 // 一周
for (key, lastAccess) in accessHistory {
if now.timeIntervalSince(lastAccess) > expirationInterval {
removeCache(for: key)
accessHistory.removeValue(forKey: key)
}
}
}
}
// 基于容量的清理
class CapacityBasedCache {
private let maxDiskSize: Int = 100 * 1024 * 1024 // 100MB
func cleanupOldFiles() {
var totalSize = 0
let files = sortedCacheFilesByAccessDate() // 按访问时间排序
for file in files {
totalSize += file.size
if totalSize > maxDiskSize {
try? FileManager.default.removeItem(at: file.url)
}
}
}
}
3. 数据缓存特别处理
class FinancialDataCache {
// 实时性要求高的数据:短时间缓存
func cacheAccountBalance(_ balance: Double, for userId: String) {
// 余额数据只缓存5分钟
cache.setObject(balance, forKey: "balance_\(userId)", expiresIn: 300)
}
// 交易记录:可适当延长缓存时间
func cacheTransactions(_ transactions: [Transaction], for userId: String) {
// 交易记录缓存1小时
cache.setObject(transactions, forKey: "transactions_\(userId)", expiresIn: 3600)
}
// 敏感数据:退出即清理
func clearSensitiveData() {
cache.removeObject(forKey: "balance_\(userId)")
cache.removeObject(forKey: "recent_transfers_\(userId)")
// 同时清理磁盘缓存
DiskCache.clearUserData(userId)
}
}
📈 缓存性能监控
class CacheMetrics {
var hitCount = 0
var missCount = 0
var totalSize: Int64 = 0
var hitRate: Double {
return Double(hitCount) / Double(hitCount + missCount)
}
func logCacheHit() {
hitCount += 1
if hitRate < 0.6 {
// 命中率过低,考虑调整缓存策略
print("警告:缓存命中率偏低 \(hitRate)")
}
}
}
🎯 要点总结
- 内存泄露:强调工具使用(Memory Graph)和常见场景(闭包、代理),结合金融APP谈敏感数据清理
- 网络加密:说明分层理念(HTTPS打底+业务层增强),重点阐述参数签名防篡改和密钥安全管理
- 通用缓存:解释三级架构(内存→磁盘→DB),强调金融数据的特殊缓存策略(短时间、及时清理)
三者关联性:良好的缓存设计减少不必要的网络请求(降低加密传输压力),正确的内存管理确保缓存对象及时释放,三者共同保障APP性能与安全。