blog icon indicating copy to clipboard operation
blog copied to clipboard

swift 常用算法小记

Open diamont1001 opened this issue 4 years ago • 0 comments

计算还有多少天生日

// 计算距离生日的天数
private func daysToBirthday(birthday: Date) -> Int {
    // 今天生日的情况(不然后面的计算会误把下个生日算到明年,也就是返回365)
    if (Calendar.current.dateComponents([.year, .month, .day], from: Date()).month == Calendar.current.dateComponents([.year, .month, .day], from: birthday).month
    && Calendar.current.dateComponents([.year, .month, .day], from: Date()).day == Calendar.current.dateComponents([.year, .month, .day], from: birthday).day) {
        return 0
    }
    
    let today = Calendar.current.startOfDay(for: Date())
    let date = Calendar.current.startOfDay(for: birthday)
    let components = Calendar.current.dateComponents([.day, .month], from: date)
    let nextDate = Calendar.current.nextDate(after: today, matching: components, matchingPolicy: .nextTimePreservingSmallerComponents)
    return Calendar.current.dateComponents([.day], from: today, to: nextDate ?? today).day ?? 0
}

计算某个时间到今天的天数

// 计算某个时间到今天的天数
private func daysToNow(from: Date) -> Int {
    let date1 = Calendar.current.startOfDay(for: from)
    let date2 = Calendar.current.startOfDay(for: Date())

    // 不能直接用 date 进行 Calendar.current.dateComponents([.day], from: from, to: Date()) 计算,这样不超过24小时的都算是返回0,比如昨天会返回0而前天会返回1
    let components = Calendar.current.dateComponents([.day], from: date1, to: date2)
    
    return components.day ?? 0
}

获取时间戳

extension Date {
    /// 获取当前 秒级 时间戳 - 10位
    var timeStamp : String {
        let timeInterval: TimeInterval = self.timeIntervalSince1970
        let timestamp = Int(timeInterval)
        return "\(timestamp)"
    }
    
    /// 获取当前 毫秒级 时间戳 - 13位
    var milliStamp : String {
        let timeInterval : TimeInterval = self.timeIntervalSince1970
        let millisecond = CLongLong(round(timeInterval*1000))
        return "\(millisecond)"
    }
}

FaceID人脸识别封装


import Foundation
import LocalAuthentication // 生物特征识别

class Authentication: ObservableObject{
    @Published var hasAuthenticate: Bool = false // 是否已鉴权
    
    /*
     * 鉴权函数,调起 FACE ID 生物识别
     * 用法:
     * 1)引入鉴权环境对象 @EnvironmentObject var authenticateObj : Authentication
     * 2)需要的时候,调用函数进行鉴权 authenticateObj.authenticate()
     * 3)判断是否已鉴权 if authenticateObj.hasAuthenticate { }
     */
    func authenticate() {
        let context = LAContext()
        var error: NSError?
        
        // 如果已经鉴权,则不用再调起
        if self.hasAuthenticate {
            return
        }

        // 检查是否可以进行生物特征识别
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            // 如果可以,执行识别
            let reason = "We need to unlock your data."

            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
                // 鉴权完成
                DispatchQueue.main.async {
                    if success {
                        // 鉴权成功
                        self.hasAuthenticate = true
                    } else {
                        // 鉴权失败
                        self.hasAuthenticate = false
                    }
                }
            }
        } else {
            // 没有生物特征识别功能
        }
    }
}

获取APP名称

extension Bundle {
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0"
    }
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String ?? "1"
    }
    var displayName: String? {
        return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
            object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Unknown"
    }
}

Double取N位小数

// double取多少位小数
extension Double {
    /// Rounds the double to decimal places value
    func rounded(toPlaces places:Int) -> Double {
        let divisor = pow(10.0, Double(places))
        return (self * divisor).rounded() / divisor
    }
}

获取屏幕宽高

注意:iPad 下屏幕宽度跟可页面可视宽度不一致,要使用 GeometryReader

// 屏幕宽度
class SGConvenience{
    #if os(watchOS)
    static var deviceWidth:CGFloat = WKInterfaceDevice.current().screenBounds.size.width
    static var deviceHeight:CGFloat = WKInterfaceDevice.current().screenBounds.size.height
    #elseif os(iOS)
    static var deviceWidth:CGFloat = UIScreen.main.bounds.size.width
    static var deviceHeight:CGFloat = UIScreen.main.bounds.size.height
    #elseif os(macOS)
    static var deviceWidth:CGFloat? = NSScreen.main?.visibleFrame.size.width // You could implement this to force a CGFloat and get the full device screen size width regardless of the window size with .frame.size.width
    static var deviceHeight:CGFloat? = NSScreen.main?.visibleFrame.size.height
    #endif
}

解决中文问题

extension String {
    // base64(可用于解决中文问题)
    func fromBase64() -> String? {
        guard let data = Data(base64Encoded: self) else {
            return nil
        }
        return String(data: data, encoding: .utf8)
    }
    func toBase64() -> String {
        return Data(self.utf8).base64EncodedString()
    }
}

打开AppStore评分

// 打开评分
if let scene = UIApplication.shared.connectedScenes
        .first(where: { $0.activationState == .foregroundActive })
        as? UIWindowScene {
    SKStoreReviewController.requestReview(in: scene)
}

diamont1001 avatar Oct 26 '21 21:10 diamont1001