macOS 移动端功能 Swift 示例
macOS Swift 移动端功能示例,包括设备信息、网络状态和振动反馈
💻 设备信息获取 swift
🟢 simple
⭐⭐⭐
获取全面的设备信息,包括型号、系统版本、硬件能力和系统规格
⏱️ 25 min
🏷️ swift, macos, ios, mobile, device
Prerequisites:
Swift basics, Foundation framework, iOS/macOS APIs
// macOS/iOS Swift Device Information Examples
// Using Foundation, UIKit, and SystemConfiguration frameworks
#if os(iOS)
import UIKit
import UIKit.UIDevice
#endif
#if os(macOS)
import AppKit
import IOKit
import IOKit.ps
#endif
import Foundation
import SystemConfiguration
// 1. Basic Device Information
class DeviceInformation {
#if os(iOS)
// iOS Device Information
static func getIOSDeviceInfo() -> DeviceInfo {
let device = UIDevice.current
var info = DeviceInfo()
info.platform = "iOS"
info.name = device.name
info.systemName = device.systemName
info.systemVersion = device.systemVersion
info.model = device.model
info.localizedModel = device.localizedModel
info.userInterfaceIdiom = device.userInterfaceIdiom == .phone ? "iPhone" : "iPad"
// Battery state
info.batteryLevel = device.batteryLevel
info.batteryState = device.batteryState.rawValue
device.isBatteryMonitoringEnabled = true
// Screen info
let screen = UIScreen.main
info.screenBounds = screen.bounds
info.screenScale = screen.scale
info.brightness = screen.brightness
return info
}
#endif
#if os(macOS)
// macOS Device Information
static func getMacOSDeviceInfo() -> DeviceInfo {
var info = DeviceInfo()
info.platform = "macOS"
// Get system info using ProcessInfo
let processInfo = ProcessInfo.processInfo
info.systemName = "macOS"
info.systemVersion = processInfo.operatingSystemVersionString
info.hostName = processInfo.hostName
info.physicalMemory = getPhysicalMemory()
info.processorCount = processInfo.processorCount
info.activeProcessorCount = processInfo.activeProcessorCount
// Get hardware info
let hardwareInfo = getHardwareInfo()
info.model = hardwareInfo.model
info.cpuType = hardwareInfo.cpuType
info.cpuFrequency = hardwareInfo.cpuFrequency
// Get serial number
info.serialNumber = getSerialNumber()
return info
}
// Get physical memory
static func getPhysicalMemory() -> UInt64 {
var size: UInt64 = 0
var mib: [Int32] = [CTL_HW, HW_MEMSIZE]
var len = MemoryLayout<UInt64>.size
sysctl(&mib, u_int(mib.count), &size, &len, nil, 0)
return size
}
// Get hardware information
static func getHardwareInfo() -> (model: String, cpuType: String, cpuFrequency: String) {
var size = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var model = [CChar](repeating: 0, count: size)
sysctlbyname("hw.model", &model, &size, nil, 0)
let modelString = String(cString: model)
// Get CPU info
var cpufamily: UInt32 = 0
var cpufamily_size = MemoryLayout<UInt32>.size
sysctlbyname("hw.cpufamily", &cpufamily, &cpufamily_size, nil, 0)
var cpufrequency: Int64 = 0
var cpufrequency_size = MemoryLayout<Int64>.size
sysctlbyname("hw.cpufrequency", &cpufrequency, &cpufrequency_size, nil, 0)
let cpuFreqGHz = Double(cpufrequency) / 1_000_000_000
return (modelString, "CPU Family: \(cpufamily)", String(format: "%.2f GHz", cpuFreqGHz))
}
// Get serial number
static func getSerialNumber() -> String {
let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"))
defer { IOObjectRelease(platformExpert) }
guard platformExpert != 0 else { return "Unknown" }
let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
kIOPlatformSerialNumberKey as CFString,
kCFAllocatorDefault,
0)
guard let serialNumber = serialNumberAsCFString?.takeUnretainedValue() as? String else {
return "Unknown"
}
return serialNumber
}
#endif
// Get common system info
static func getSystemInfo() -> SystemInfo {
var sysInfo = SystemInfo()
let processInfo = ProcessInfo.processInfo
sysInfo.upTime = processInfo.systemUptime
sysInfo.processorCount = processInfo.processorCount
sysInfo.activeProcessorCount = processInfo.activeProcessorCount
sysInfo.arguments = processInfo.arguments
sysInfo.environment = processInfo.environment
sysInfo.processName = processInfo.processName
sysInfo.globalNumberOfRunningTasks = ProcessInfo.processInfo.processorCount
return sysInfo
}
// Get memory usage
static func getMemoryUsage() -> MemoryUsage {
var stats = vm_statistics64()
var count = UInt32(MemoryLayout<vm_statistics64>.size / MemoryLayout<integer_t>.size)
let result = withUnsafeMutablePointer(to: &stats) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
}
}
guard result == KERN_SUCCESS else {
return MemoryUsage()
}
let pageSize = vm_kernel_page_size
let totalMemory = getPhysicalMemory()
let usedMemory = UInt64(stats.active_count + stats.wire_count) * UInt64(pageSize)
let freeMemory = UInt64(stats.free_count) * UInt64(pageSize)
let cachedMemory = UInt64(stats.inactive_count + stats.speculative_count) * UInt64(pageSize)
return MemoryUsage(
total: totalMemory,
used: usedMemory,
free: freeMemory,
cached: cachedMemory,
active: UInt64(stats.active_count) * UInt64(pageSize),
wired: UInt64(stats.wire_count) * UInt64(pageSize)
)
}
}
// 2. Network Status Monitoring
class NetworkStatus {
// Check if network is available
static func isNetworkAvailable() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return isReachable && !needsConnection
}
// Get detailed network status
static func getNetworkStatus() -> NetworkStatusInfo {
var status = NetworkStatusInfo()
// Check reachability
status.isReachable = isNetworkAvailable()
// Get connection type
status.connectionType = getConnectionType()
// Check WiFi status (iOS only)
#if os(iOS)
status.isWiFiEnabled = isWiFiEnabled()
#endif
return status
}
// Get connection type
static func getConnectionType() -> String {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
}
}) else {
return "Unknown"
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return "Unknown"
}
let isWWAN = flags.contains(.isWWAN)
let isReachable = flags.contains(.reachable)
if isReachable && isWWAN {
return "Cellular"
} else if isReachable {
return "WiFi"
} else {
return "No Connection"
}
}
#if os(iOS)
// Check if WiFi is enabled
static func isWiFiEnabled() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
}
}) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
return flags.contains(.reachable) && !flags.contains(.isWWAN)
}
#endif
// Monitor network changes
static func startNetworkMonitoring(callback: @escaping (NetworkStatusInfo) -> Void) {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
}
}) else {
return
}
var context = NetworkCallbackContext(callback: callback)
SCNetworkReachabilitySetCallback(
defaultRouteReachability,
{ (_, flags, info) in
guard let info = info else { return }
let context = info.assumingMemoryBound(to: NetworkCallbackContext.self).pointee
let status = NetworkStatusInfo(
isReachable: flags.contains(.reachable),
connectionType: flags.contains(.isWWAN) ? "Cellular" : "WiFi",
isWiFiEnabled: !flags.contains(.isWWAN) && flags.contains(.reachable)
)
context.callback(status)
},
&context
)
SCNetworkReachabilityScheduleWithRunLoop(defaultRouteReachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
}
}
// 3. Vibration and Haptic Feedback
class VibrationController {
#if os(iOS)
// Basic vibration
static func vibrate() {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
}
// Vibrate with pattern
static func vibrate(pattern: [VibrationPattern]) {
for item in pattern {
DispatchQueue.main.asyncAfter(deadline: .now() + item.delay) {
if item.vibrate {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
}
}
}
}
// Haptic feedback (iOS 10+)
@available(iOS 10.0, *)
static func haptic(style: UIImpactFeedbackGenerator.FeedbackStyle) {
let generator = UIImpactFeedbackGenerator(style: style)
generator.prepare()
generator.impactOccurred()
}
// Notification haptic
@available(iOS 10.0, *)
static func notificationHaptic(type: UINotificationFeedbackGenerator.FeedbackType) {
let generator = UINotificationFeedbackGenerator()
generator.prepare()
generator.notificationOccurred(type)
}
// Selection haptic
@available(iOS 10.0, *)
static func selectionHaptic() {
let generator = UISelectionFeedbackGenerator()
generator.prepare()
generator.selectionChanged()
}
#else
// macOS doesn't support vibration, but we can provide audio feedback
static func vibrate() {
print("Vibration not supported on macOS")
// Play system sound instead
NSSound.beep()
}
static func vibrate(pattern: [VibrationPattern]) {
print("Vibration pattern not supported on macOS")
NSSound.beep()
}
#endif
// Predefined vibration patterns
static func successVibration() {
#if os(iOS)
if #available(iOS 10.0, *) {
notificationHaptic(type: .success)
} else {
vibrate()
}
#else
NSSound.beep()
#endif
}
static func errorVibration() {
#if os(iOS)
if #available(iOS 10.0, *) {
notificationHaptic(type: .error)
} else {
vibrate(pattern: [
VibrationPattern(vibrate: true, delay: 0),
VibrationPattern(vibrate: false, delay: 0.1),
VibrationPattern(vibrate: true, delay: 0.1)
])
}
#else
NSSound.beep()
NSSound.beep()
#endif
}
static func warningVibration() {
#if os(iOS)
if #available(iOS 10.0, *) {
notificationHaptic(type: .warning)
} else {
vibrate()
}
#else
NSSound.beep()
#endif
}
}
// Data Structures
struct DeviceInfo {
var platform: String = ""
var name: String = ""
var systemName: String = ""
var systemVersion: String = ""
var model: String = ""
var localizedModel: String = ""
var userInterfaceIdiom: String = ""
var batteryLevel: Float = -1
var batteryState: Int = 0
var screenBounds: CGRect = .zero
var screenScale: CGFloat = 1.0
var brightness: CGFloat = 0.5
var hostName: String = ""
var physicalMemory: UInt64 = 0
var processorCount: Int = 0
var activeProcessorCount: Int = 0
var cpuType: String = ""
var cpuFrequency: String = ""
var serialNumber: String = ""
}
struct SystemInfo {
var upTime: TimeInterval = 0
var processorCount: Int = 0
var activeProcessorCount: Int = 0
var arguments: [String] = []
var environment: [String: String] = [:]
var processName: String = ""
var globalNumberOfRunningTasks: Int = 0
}
struct MemoryUsage {
var total: UInt64 = 0
var used: UInt64 = 0
var free: UInt64 = 0
var cached: UInt64 = 0
var active: UInt64 = 0
var wired: UInt64 = 0
}
struct NetworkStatusInfo {
var isReachable: Bool = false
var connectionType: String = "Unknown"
var isWiFiEnabled: Bool = false
}
struct VibrationPattern {
var vibrate: Bool
var delay: TimeInterval
}
struct NetworkCallbackContext {
var callback: (NetworkStatusInfo) -> Void
}
// Constants
let CTL_HW: Int32 = 6
let HW_MEMSIZE: Int32 = 24
// Helper function
func sysctlbyname(_ name: String, _ oldp: UnsafeMutableRawPointer?, _ oldlenp: UnsafeMutablePointer<Int>?, _ newp: UnsafeRawPointer?, _ newlen: Int) -> Int32 {
return Darwin.sysctlbyname(name, oldp, oldlenp, newp, newlen)
}
func sysctl(_ name: UnsafeMutablePointer<Int32>, _ namelen: UInt, _ oldp: UnsafeMutableRawPointer?, _ oldlenp: UnsafeMutablePointer<Int>, _ newp: UnsafeRawPointer?, _ newlen: Int) -> Int32 {
return Darwin.sysctl(name, namelen, oldp, oldlenp, newp, newlen)
}
// Main demonstration
func demonstrateDeviceFeatures() {
print("=== macOS/iOS Swift Device Features ===\n")
// 1. Device Information
print("--- 1. Device Information ---")
#if os(iOS)
let deviceInfo = DeviceInformation.getIOSDeviceInfo()
print("Platform: \(deviceInfo.platform)")
print("Name: \(deviceInfo.name)")
print("System: \(deviceInfo.systemName) \(deviceInfo.systemVersion)")
print("Model: \(deviceInfo.model)")
print("Idiom: \(deviceInfo.userInterfaceIdiom)")
print("Battery: \(deviceInfo.batteryLevel * 100)%")
#elseif os(macOS)
let deviceInfo = DeviceInformation.getMacOSDeviceInfo()
print("Platform: \(deviceInfo.platform)")
print("System: \(deviceInfo.systemVersion)")
print("Host Name: \(deviceInfo.hostName)")
print("Model: \(deviceInfo.model)")
print("CPU: \(deviceInfo.cpuType)")
print("CPU Frequency: \(deviceInfo.cpuFrequency)")
print("Serial Number: \(deviceInfo.serialNumber)")
print("Processors: \(deviceInfo.processorCount)")
print("Physical Memory: \(formatBytes(deviceInfo.physicalMemory))")
#endif
// 2. System Info
print("\n--- 2. System Information ---")
let sysInfo = DeviceInformation.getSystemInfo()
print("Uptime: \(formatUptime(sysInfo.upTime))")
print("Processors: \(sysInfo.processorCount)")
print("Active Processors: \(sysInfo.activeProcessorCount)")
print("Process Name: \(sysInfo.processName)")
// 3. Memory Usage
print("\n--- 3. Memory Usage ---")
let memory = DeviceInformation.getMemoryUsage()
print("Total: \(formatBytes(memory.total))")
print("Used: \(formatBytes(memory.used))")
print("Free: \(formatBytes(memory.free))")
print("Cached: \(formatBytes(memory.cached))")
print("Active: \(formatBytes(memory.active))")
print("Wired: \(formatBytes(memory.wired))")
// 4. Network Status
print("\n--- 4. Network Status ---")
let networkStatus = NetworkStatus.getNetworkStatus()
print("Reachable: \(networkStatus.isReachable)")
print("Connection Type: \(networkStatus.connectionType)")
#if os(iOS)
print("WiFi Enabled: \(networkStatus.isWiFiEnabled)")
#endif
// 5. Vibration Test
print("\n--- 5. Vibration Test ---")
print("Testing vibration...")
VibrationController.vibrate()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
print("Testing success vibration...")
VibrationController.successVibration()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
print("Testing warning vibration...")
VibrationController.warningVibration()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
print("Testing error vibration...")
VibrationController.errorVibration()
}
}
}
print("\n=== Device Features Demo Completed ===")
}
// Helper functions
func formatBytes(_ bytes: UInt64) -> String {
let kb = Double(bytes) / 1024
let mb = kb / 1024
let gb = mb / 1024
if gb >= 1 {
return String(format: "%.2f GB", gb)
} else if mb >= 1 {
return String(format: "%.2f MB", mb)
} else if kb >= 1 {
return String(format: "%.2f KB", kb)
} else {
return "\(bytes) bytes"
}
}
func formatUptime(_ seconds: TimeInterval) -> String {
let days = Int(seconds) / 86400
let hours = Int(seconds) % 86400 / 3600
let minutes = Int(seconds) % 3600 / 60
if days > 0 {
return "\(days)d \(hours)h \(minutes)m"
} else if hours > 0 {
return "\(hours)h \(minutes)m"
} else {
return "\(minutes)m"
}
}
// Run demonstration
demonstrateDeviceFeatures()
#if os(iOS)
import AVFoundation
#endif
💻 网络状态监控 swift
🟡 intermediate
⭐⭐⭐
监控网络连接性,检测连接类型变化,并实现可达性回调
⏱️ 30 min
🏷️ swift, macos, ios, network, monitoring
Prerequisites:
Swift basics, SystemConfiguration framework, Async programming
// macOS/iOS Swift Network Status Monitoring Examples
// Using SystemConfiguration and Network frameworks
import Foundation
import SystemConfiguration
#if os(iOS)
import Network
#endif
// 1. Reachability Manager
class ReachabilityManager {
var reachability: SCNetworkReachability?
var isMonitoring = false
var onNetworkChange: ((Bool) -> Void)?
// Initialize with default route
init?() {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let reachability = withUnsafePointer(to: &zeroAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
}
}) else {
return nil
}
self.reachability = reachability
}
// Start monitoring network changes
func startMonitoring(callback: @escaping (Bool) -> Void) {
guard let reachability = reachability else { return }
self.onNetworkChange = callback
isMonitoring = true
var context = SCNetworkReachabilityContext(
version: 0,
info: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
retain: nil,
release: nil,
copyDescription: nil
)
let callbackFunction: SCNetworkReachabilityCallBack = { (_, flags, info) in
guard let info = info else { return }
let manager = Unmanaged<ReachabilityManager>.fromOpaque(info).takeUnretainedValue()
let isReachable = flags.contains(.reachable) && !flags.contains(.connectionRequired)
DispatchQueue.main.async {
manager.onNetworkChange?(isReachable)
}
}
if SCNetworkReachabilitySetCallback(reachability, callbackFunction, &context) {
SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
}
}
// Stop monitoring
func stopMonitoring() {
guard let reachability = reachability, isMonitoring else { return }
SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
isMonitoring = false
onNetworkChange = nil
}
// Check current reachability
var isReachable: Bool {
guard let reachability = reachability else { return false }
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
return false
}
return flags.contains(.reachable) && !flags.contains(.connectionRequired)
}
// Get connection type
var connectionType: ConnectionType {
guard let reachability = reachability else { return .unknown }
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
return .unknown
}
if !flags.contains(.reachable) {
return .none
}
if flags.contains(.isWWAN) {
return .cellular
} else {
return .wifi
}
}
deinit {
stopMonitoring()
}
}
// Connection Type Enum
enum ConnectionType {
case none
case wifi
case cellular
case unknown
var description: String {
switch self {
case .none: return "No Connection"
case .wifi: return "WiFi"
case .cellular: return "Cellular"
case .unknown: return "Unknown"
}
}
}
// 2. Network Monitor with Detailed Info
class NetworkMonitor {
private var reachabilityManager: ReachabilityManager?
private var networkHistory: [NetworkEvent] = []
private let maxHistorySize = 100
// Start monitoring
func startMonitoring() {
reachabilityManager = ReachabilityManager()
reachabilityManager?.startMonitoring { [weak self] isReachable in
self?.handleNetworkChange(isReachable: isReachable)
}
logInitialStatus()
}
// Stop monitoring
func stopMonitoring() {
reachabilityManager?.stopMonitoring()
reachabilityManager = nil
}
// Handle network change
private func handleNetworkChange(isReachable: Bool) {
let event = NetworkEvent(
timestamp: Date(),
isReachable: isReachable,
connectionType: reachabilityManager?.connectionType ?? .unknown
)
networkHistory.append(event)
// Trim history
if networkHistory.count > maxHistorySize {
networkHistory.removeFirst()
}
let status = isReachable ? "Connected" : "Disconnected"
let connection = event.connectionType.description
print("[\(formatTimestamp(event.timestamp))] Network: \(status) (\(connection))")
}
// Log initial status
private func logInitialStatus() {
let isReachable = reachabilityManager?.isReachable ?? false
let connectionType = reachabilityManager?.connectionType ?? .unknown
let event = NetworkEvent(
timestamp: Date(),
isReachable: isReachable,
connectionType: connectionType
)
networkHistory.append(event)
print("=== Network Monitor Started ===")
print("Current Status: \(isReachable ? "Connected" : "Disconnected")")
print("Connection Type: \(connectionType.description)")
}
// Get current status
func getCurrentStatus() -> NetworkStatus {
return NetworkStatus(
isReachable: reachabilityManager?.isReachable ?? false,
connectionType: reachabilityManager?.connectionType ?? .unknown,
lastChange: networkHistory.last?.timestamp ?? Date()
)
}
// Get network history
func getNetworkHistory() -> [NetworkEvent] {
return networkHistory
}
// Get statistics
func getStatistics() -> NetworkStatistics {
var connectedTime: TimeInterval = 0
var disconnectedTime: TimeInterval = 0
var connectionCount = 0
var disconnectionCount = 0
for i in 1..<networkHistory.count {
let previous = networkHistory[i - 1]
let current = networkHistory[i]
let duration = current.timestamp.timeIntervalSince(previous.timestamp)
if previous.isReachable {
connectedTime += duration
if !current.isReachable {
disconnectionCount += 1
}
} else {
disconnectedTime += duration
if current.isReachable {
connectionCount += 1
}
}
}
// Add time from last event to now
if let last = networkHistory.last {
let duration = Date().timeIntervalSince(last.timestamp)
if last.isReachable {
connectedTime += duration
} else {
disconnectedTime += duration
}
}
let totalConnectedEvents = networkHistory.filter { $0.isReachable }.count
let totalDisconnectedEvents = networkHistory.filter { !$0.isReachable }.count
return NetworkStatistics(
connectedTime: connectedTime,
disconnectedTime: disconnectedTime,
connectionCount: connectionCount,
disconnectionCount: disconnectionCount,
totalConnectedEvents: totalConnectedEvents,
totalDisconnectedEvents: totalDisconnectedEvents
)
}
}
// Data Structures
struct NetworkEvent {
let timestamp: Date
let isReachable: Bool
let connectionType: ConnectionType
}
struct NetworkStatus {
let isReachable: Bool
let connectionType: ConnectionType
let lastChange: Date
}
struct NetworkStatistics {
let connectedTime: TimeInterval
let disconnectedTime: TimeInterval
let connectionCount: Int
let disconnectionCount: Int
let totalConnectedEvents: Int
let totalDisconnectedEvents: Int
var uptimePercentage: Double {
let total = connectedTime + disconnectedTime
guard total > 0 else { return 0 }
return (connectedTime / total) * 100
}
}
// 3. Bandwidth Monitor (Simplified)
class BandwidthMonitor {
private var startTime: Date?
private var startBytes: UInt64 = 0
private var currentBytes: UInt64 = 0
// Start monitoring bandwidth
func startMonitoring() {
startTime = Date()
startBytes = getCurrentBytesReceived()
print("Bandwidth monitoring started")
}
// Stop monitoring and get results
func stopMonitoring() -> BandwidthResult {
guard let start = startTime else {
return BandwidthResult(duration: 0, bytesReceived: 0, averageSpeed: 0)
}
currentBytes = getCurrentBytesReceived()
let duration = Date().timeIntervalSince(start)
let bytesReceived = currentBytes - startBytes
let averageSpeed = bytesReceived / UInt64(duration)
startTime = nil
startBytes = 0
let result = BandwidthResult(
duration: duration,
bytesReceived: bytesReceived,
averageSpeed: averageSpeed
)
print("Bandwidth monitoring stopped:")
print(" Duration: \(String(format: "%.1f", duration))s")
print(" Bytes Received: \(formatBytes(bytesReceived))")
print(" Average Speed: \(formatBytes(averageSpeed))/s")
return result
}
// Get current bytes received (simplified)
private func getCurrentBytesReceived() -> UInt64 {
// In a real implementation, you'd use network interface statistics
// This is a placeholder
return UInt64.random(in: 1000000...10000000)
}
}
struct BandwidthResult {
let duration: TimeInterval
let bytesReceived: UInt64
let averageSpeed: UInt64
}
// 4. Connectivity Test
class ConnectivityTest {
// Test connectivity to a host
static func testConnection(to host: String, timeout: TimeInterval = 5.0) -> Bool {
guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else {
return false
}
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(reachability, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic)
return isReachable && (!needsConnection || canConnectAutomatically)
}
// Test multiple hosts
static func testMultipleHosts(_ hosts: [String]) -> [String: Bool] {
var results: [String: Bool] = [:]
for host in hosts {
results[host] = testConnection(to: host)
}
return results
}
// Ping test (simplified)
static func ping(_ host: String, count: Int = 4) -> PingResult {
print("Pinging \(host)...")
var successfulPings = 0
var totalLatency: TimeInterval = 0
for _ in 0..<count {
let start = Date()
if testConnection(to: host, timeout: 1.0) {
let latency = Date().timeIntervalSince(start)
totalLatency += latency
successfulPings += 1
}
Thread.sleep(forTimeInterval: 0.5)
}
let averageLatency = successfulPings > 0 ? totalLatency / Double(successfulPings) : 0
let packetLoss = ((count - successfulPings) / count) * 100
let result = PingResult(
host: host,
packetsSent: count,
packetsReceived: successfulPings,
packetLoss: packetLoss,
averageLatency: averageLatency
)
print("Ping statistics for \(host):")
print(" Packets: Sent = \(count), Received = \(successfulPings), Lost = \(count - successfulPings)")
print(" Packet Loss: \(packetLoss)%")
if successfulPings > 0 {
print(" Average Latency: \(String(format: "%.2f", averageLatency * 1000))ms")
}
return result
}
}
struct PingResult {
let host: String
let packetsSent: Int
let packetsReceived: Int
let packetLoss: Int
let averageLatency: TimeInterval
}
// Helper functions
func formatTimestamp(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
return formatter.string(from: date)
}
func formatBytes(_ bytes: UInt64) -> String {
let kb = Double(bytes) / 1024
let mb = kb / 1024
let gb = mb / 1024
if gb >= 1 {
return String(format: "%.2f GB", gb)
} else if mb >= 1 {
return String(format: "%.2f MB", mb)
} else if kb >= 1 {
return String(format: "%.2f KB", kb)
} else {
return "\(bytes) B"
}
}
// Main demonstration
func demonstrateNetworkMonitoring() {
print("=== macOS/iOS Swift Network Status Monitoring ===\n")
// 1. Basic reachability check
print("--- 1. Basic Reachability Check ---")
if let manager = ReachabilityManager() {
print("Is Reachable: \(manager.isReachable)")
print("Connection Type: \(manager.connectionType.description)")
}
// 2. Start monitoring
print("\n--- 2. Network Monitoring ---")
let monitor = NetworkMonitor()
monitor.startMonitoring()
// Keep monitoring for a few seconds
print("Monitoring network changes for 10 seconds...")
Thread.sleep(forTimeInterval: 10)
// 3. Get current status
print("\n--- 3. Current Status ---")
let status = monitor.getCurrentStatus()
print("Reachable: \(status.isReachable)")
print("Connection: \(status.connectionType.description)")
print("Last Change: \(formatTimestamp(status.lastChange))")
// 4. Get statistics
print("\n--- 4. Network Statistics ---")
let stats = monitor.getStatistics()
print("Connected Time: \(String(format: "%.1f", stats.connectedTime))s")
print("Disconnected Time: \(String(format: "%.1f", stats.disconnectedTime))s")
print("Connection Count: \(stats.connectionCount)")
print("Disconnection Count: \(stats.disconnectionCount)")
print("Uptime: \(String(format: "%.1f", stats.uptimePercentage))%")
// 5. Test multiple hosts
print("\n--- 5. Host Connectivity Tests ---")
let hosts = ["apple.com", "google.com", "github.com", "localhost"]
let results = ConnectivityTest.testMultipleHosts(hosts)
for (host, reachable) in results {
print("\(host): \(reachable ? "✓ Reachable" : "✗ Unreachable")")
}
// 6. Ping test
print("\n--- 6. Ping Test ---")
let pingResult = ConnectivityTest.ping("apple.com", count: 4)
// 7. Bandwidth monitoring
print("\n--- 7. Bandwidth Monitoring ---")
let bandwidthMonitor = BandwidthMonitor()
bandwidthMonitor.startMonitoring()
print("Monitoring bandwidth for 5 seconds...")
Thread.sleep(forTimeInterval: 5)
bandwidthMonitor.stopMonitoring()
// Stop monitoring
monitor.stopMonitoring()
print("\n=== Network Monitoring Demo Completed ===")
}
// Run demonstration
demonstrateNetworkMonitoring()
💻 振动和触觉反馈 swift
🔴 complex
⭐⭐⭐⭐
实现设备振动模式和用户通知的触觉反馈
⏱️ 30 min
🏷️ swift, macos, ios, haptic, vibration
Prerequisites:
Swift basics, CoreHaptics framework, iOS 13+ APIs
// macOS/iOS Swift Vibration and Haptic Feedback Examples
// Using CoreHaptics (iOS 13+) and AudioToolbox
#if os(iOS)
import UIKit
import CoreHaptics
import AudioToolbox
#endif
#if os(macOS)
import AppKit
#endif
import Foundation
// 1. Haptic Engine Manager
class HapticEngineManager {
#if os(iOS)
@available(iOS 13.0, *)
private var hapticEngine: CHHapticEngine?
// Initialize haptic engine
@available(iOS 13.0, *)
func initializeHapticEngine() -> Bool {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
print("Haptics not supported on this device")
return false
}
do {
hapticEngine = try CHHapticEngine()
// Handle engine stopped
hapticEngine?.stoppedHandler = { reason in
print("Haptic engine stopped: \(reason.rawValue)")
}
// Handle engine reset
hapticEngine?.resetHandler = {
print("Haptic engine reset")
do {
try self.hapticEngine?.start()
} catch {
print("Error starting haptic engine after reset: \(error)")
}
}
try hapticEngine?.start()
print("Haptic engine initialized successfully")
return true
} catch {
print("Error creating haptic engine: \(error)")
return false
}
}
// Stop haptic engine
@available(iOS 13.0, *)
func stopHapticEngine() {
hapticEngine?.stop(completionHandler: { error in
if let error = error {
print("Error stopping haptic engine: \(error)")
}
})
}
#else
func initializeHapticEngine() -> Bool {
print("Haptics not supported on macOS")
return false
}
func stopHapticEngine() {
print("Haptics not supported on macOS")
}
#endif
}
// 2. Vibration Patterns
class VibrationPatternManager {
#if os(iOS)
// Play vibration pattern using AudioToolbox
static func playVibrationPattern(_ pattern: VibrationPattern) {
for item in pattern.items {
DispatchQueue.main.asyncAfter(deadline: .now() + item.delay) {
if item.intensity > 0 {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
}
}
}
}
// Predefined patterns
static func notificationPattern() -> VibrationPattern {
VibrationPattern(items: [
VibrationItem(intensity: 1, delay: 0),
VibrationItem(intensity: 0, delay: 0.1),
VibrationItem(intensity: 1, delay: 0.1)
])
}
static func alertPattern() -> VibrationPattern {
VibrationPattern(items: [
VibrationItem(intensity: 1, delay: 0),
VibrationItem(intensity: 0, delay: 0.15),
VibrationItem(intensity: 1, delay: 0.15),
VibrationItem(intensity: 0, delay: 0.15),
VibrationItem(intensity: 1, delay: 0.15)
])
}
static func successPattern() -> VibrationPattern {
VibrationPattern(items: [
VibrationItem(intensity: 1, delay: 0),
VibrationItem(intensity: 0, delay: 0.05),
VibrationItem(intensity: 1, delay: 0.05)
])
}
static func errorPattern() -> VibrationPattern {
VibrationPattern(items: [
VibrationItem(intensity: 1, delay: 0),
VibrationItem(intensity: 0, delay: 0.1),
VibrationItem(intensity: 1, delay: 0.1),
VibrationItem(intensity: 0, delay: 0.1),
VibrationItem(intensity: 1, delay: 0.1),
VibrationItem(intensity: 0, delay: 0.1),
VibrationItem(intensity: 1, delay: 0.1)
])
}
static func heartbeatPattern() -> VibrationPattern {
VibrationPattern(items: [
VibrationItem(intensity: 1, delay: 0),
VibrationItem(intensity: 0, delay: 0.15),
VibrationItem(intensity: 1, delay: 0.15),
VibrationItem(intensity: 0, delay: 0.3),
VibrationItem(intensity: 1, delay: 0.3),
VibrationItem(intensity: 0, delay: 0.15),
VibrationItem(intensity: 1, delay: 0.15)
])
}
#else
static func playVibrationPattern(_ pattern: VibrationPattern) {
print("Vibration not supported on macOS")
NSSound.beep()
}
static func notificationPattern() -> VibrationPattern {
VibrationPattern(items: [])
}
static func alertPattern() -> VibrationPattern {
VibrationPattern(items: [])
}
static func successPattern() -> VibrationPattern {
VibrationPattern(items: [])
}
static func errorPattern() -> VibrationPattern {
VibrationPattern(items: [])
}
static func heartbeatPattern() -> VibrationPattern {
VibrationPattern(items: [])
}
#endif
}
// 3. Haptic Feedback Manager
class HapticFeedbackManager {
#if os(iOS)
// Impact feedback
@available(iOS 10.0, *)
static func impact(style: UIImpactFeedbackGenerator.FeedbackStyle) {
let generator = UIImpactFeedbackGenerator(style: style)
generator.prepare()
generator.impactOccurred()
}
// Light impact
@available(iOS 10.0, *)
static func lightImpact() {
impact(style: .light)
}
// Medium impact
@available(iOS 10.0, *)
static func mediumImpact() {
impact(style: .medium)
}
// Heavy impact
@available(iOS 10.0, *)
static func heavyImpact() {
impact(style: .heavy)
}
// Soft impact (iOS 13+)
@available(iOS 13.0, *)
static func softImpact() {
impact(style: .soft)
}
// Rigid impact (iOS 13+)
@available(iOS 13.0, *)
static func rigidImpact() {
impact(style: .rigid)
}
// Notification feedback
@available(iOS 10.0, *)
static func notification(_ type: UINotificationFeedbackGenerator.FeedbackType) {
let generator = UINotificationFeedbackGenerator()
generator.prepare()
generator.notificationOccurred(type)
}
// Success notification
@available(iOS 10.0, *)
static func successNotification() {
notification(.success)
}
// Warning notification
@available(iOS 10.0, *)
static func warningNotification() {
notification(.warning)
}
// Error notification
@available(iOS 10.0, *)
static func errorNotification() {
notification(.error)
}
// Selection feedback
@available(iOS 10.0, *)
static func selectionChanged() {
let generator = UISelectionFeedbackGenerator()
generator.prepare()
generator.selectionChanged()
}
#else
static func impact(style: Int) {
print("Haptic impact not supported on macOS")
NSSound.beep()
}
static func lightImpact() {
NSSound.beep()
}
static func mediumImpact() {
NSSound.beep()
}
static func heavyImpact() {
NSSound.beep()
}
static func notification(_ type: Int) {
NSSound.beep()
}
static func successNotification() {
NSSound.beep()
}
static func warningNotification() {
NSSound.beep()
NSSound.beep()
}
static func errorNotification() {
NSSound.beep()
NSSound.beep()
NSSound.beep()
}
static func selectionChanged() {
NSSound.beep()
}
#endif
}
// 4. Custom Haptic Patterns
class CustomHapticPatterns {
#if os(iOS)
@available(iOS 13.0, *)
static func playCustomHapticPattern(intensity: Float, sharpness: Float, duration: TimeInterval) {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
print("Haptics not supported")
return
}
do {
let pattern = try CHHapticPattern(
events: [
CHHapticEvent(eventType: .hapticTransient, parameters: [
CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity),
CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness)
], relativeTime: 0)
],
parameters: []
)
let engine = try CHHapticEngine()
try engine.start()
let player = try engine.makePlayer(with: pattern)
try player.start(atTime: 0)
print("Playing custom haptic pattern")
} catch {
print("Error playing custom pattern: \(error)")
}
}
@available(iOS 13.0, *)
static func playContinuousHaptic(intensity: Float, sharpness: Float, duration: TimeInterval) {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
print("Haptics not supported")
return
}
do {
let pattern = try CHHapticPattern(
events: [
CHHapticEvent(eventType: .hapticContinuous, parameters: [
CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity),
CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness)
], relativeTime: 0, duration: duration)
],
parameters: []
)
let engine = try CHHapticEngine()
try engine.start()
let player = try engine.makePlayer(with: pattern)
try player.start(atTime: 0)
print("Playing continuous haptic for \(duration)s")
} catch {
print("Error playing continuous haptic: \(error)")
}
}
@available(iOS 13.0, *)
static func playComplexPattern() {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else {
print("Haptics not supported")
return
}
do {
// Create a complex pattern with multiple events
let pattern = try CHHapticPattern(
events: [
// Tap
CHHapticEvent(eventType: .hapticTransient, parameters: [
CHHapticEventParameter(parameterID: .hapticIntensity, value: 1.0),
CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.5)
], relativeTime: 0),
// Hold
CHHapticEvent(eventType: .hapticContinuous, parameters: [
CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.8),
CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.3)
], relativeTime: 0.1, duration: 0.2),
// Release
CHHapticEvent(eventType: .hapticTransient, parameters: [
CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.6),
CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.8)
], relativeTime: 0.4)
],
parameters: []
)
let engine = try CHHapticEngine()
try engine.start()
let player = try engine.makePlayer(with: pattern)
try player.start(atTime: 0)
print("Playing complex haptic pattern")
} catch {
print("Error playing complex pattern: \(error)")
}
}
#else
@available(iOS 13.0, *)
static func playCustomHapticPattern(intensity: Float, sharpness: Float, duration: TimeInterval) {
print("Custom haptics not supported on macOS")
}
@available(iOS 13.0, *)
static func playContinuousHaptic(intensity: Float, sharpness: Float, duration: TimeInterval) {
print("Continuous haptics not supported on macOS")
}
@available(iOS 13.0, *)
static func playComplexPattern() {
print("Complex haptics not supported on macOS")
}
#endif
}
// 5. Haptic Notification Manager
class HapticNotificationManager {
// Complete notification with visual, audio, and haptic feedback
static func showNotification(type: NotificationType) {
print("\n=== \(type.title) ===")
switch type {
case .success:
#if os(iOS)
if #available(iOS 10.0, *) {
HapticFeedbackManager.successNotification()
} else {
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.successPattern())
}
#else
NSSound.beep()
#endif
case .warning:
#if os(iOS)
if #available(iOS 10.0, *) {
HapticFeedbackManager.warningNotification()
} else {
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.alertPattern())
}
#else
NSSound.beep()
NSSound.beep()
#endif
case .error:
#if os(iOS)
if #available(iOS 10.0, *) {
HapticFeedbackManager.errorNotification()
} else {
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.errorPattern())
}
#else
NSSound.beep()
NSSound.beep()
NSSound.beep()
#endif
case .message:
#if os(iOS)
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.notificationPattern())
#else
NSSound.beep()
#endif
case .reminder:
#if os(iOS)
if #available(iOS 10.0, *) {
HapticFeedbackManager.mediumImpact()
}
#else
NSSound.beep()
#endif
}
}
// Show progress haptic
static func showProgressHaptic(progress: Float) {
#if os(iOS)
if #available(iOS 10.0, *) {
let intensity = CHHapticEventParameter.ParameterID.hapticIntensity
// Gradually increase haptic based on progress
if progress >= 1.0 {
HapticFeedbackManager.successNotification()
} else if progress > 0.75 {
HapticFeedbackManager.lightImpact()
}
}
#endif
}
}
// Data Structures
struct VibrationPattern {
let items: [VibrationItem]
}
struct VibrationItem {
let intensity: Int
let delay: TimeInterval
}
enum NotificationType {
case success
case warning
case error
case message
case reminder
var title: String {
switch self {
case .success: return "Success"
case .warning: return "Warning"
case .error: return "Error"
case .message: return "Message"
case .reminder: return "Reminder"
}
}
}
// Main demonstration
func demonstrateHapticFeedback() {
print("=== macOS/iOS Swift Vibration & Haptic Feedback ===\n")
// Initialize haptic engine
#if os(iOS)
if #available(iOS 13.0, *) {
let engineManager = HapticEngineManager()
_ = engineManager.initializeHapticEngine()
}
#endif
// 1. Basic impact feedback
print("--- 1. Impact Feedback ---")
print("Light impact...")
HapticFeedbackManager.lightImpact()
Thread.sleep(forTimeInterval: 0.5)
print("Medium impact...")
HapticFeedbackManager.mediumImpact()
Thread.sleep(forTimeInterval: 0.5)
print("Heavy impact...")
HapticFeedbackManager.heavyImpact()
Thread.sleep(forTimeInterval: 0.5)
// 2. Selection feedback
print("\n--- 2. Selection Feedback ---")
print("Selection changed (3 times)...")
HapticFeedbackManager.selectionChanged()
Thread.sleep(forTimeInterval: 0.2)
HapticFeedbackManager.selectionChanged()
Thread.sleep(forTimeInterval: 0.2)
HapticFeedbackManager.selectionChanged()
// 3. Notification feedback
print("\n--- 3. Notification Feedback ---")
print("Success notification...")
HapticNotificationManager.showNotification(type: .success)
Thread.sleep(forTimeInterval: 1.0)
print("Warning notification...")
HapticNotificationManager.showNotification(type: .warning)
Thread.sleep(forTimeInterval: 1.0)
print("Error notification...")
HapticNotificationManager.showNotification(type: .error)
Thread.sleep(forTimeInterval: 1.0)
// 4. Vibration patterns
print("\n--- 4. Vibration Patterns ---")
print("Notification pattern...")
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.notificationPattern())
Thread.sleep(forTimeInterval: 1.0)
print("Alert pattern...")
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.alertPattern())
Thread.sleep(forTimeInterval: 1.0)
print("Heartbeat pattern...")
VibrationPatternManager.playVibrationPattern(VibrationPatternManager.heartbeatPattern())
// 5. Custom haptics (iOS 13+)
#if os(iOS)
if #available(iOS 13.0, *) {
print("\n--- 5. Custom Haptics ---")
Thread.sleep(forTimeInterval: 1.0)
print("Custom pattern (intensity: 0.8, sharpness: 0.5)...")
CustomHapticPatterns.playCustomHapticPattern(intensity: 0.8, sharpness: 0.5, duration: 0.3)
Thread.sleep(forTimeInterval: 0.5)
print("Continuous haptic (0.5s)...")
CustomHapticPatterns.playContinuousHaptic(intensity: 0.7, sharpness: 0.4, duration: 0.5)
Thread.sleep(forTimeInterval: 0.6)
print("Complex pattern...")
CustomHapticPatterns.playComplexPattern()
}
#endif
// 6. Progress haptics
print("\n--- 6. Progress Haptics ---")
print("Simulating progress...")
for i in 1...5 {
let progress = Float(i) / 5.0
print("Progress: \(Int(progress * 100))%")
HapticNotificationManager.showProgressHaptic(progress: progress)
Thread.sleep(forTimeInterval: 0.3)
}
print("\n=== Haptic Feedback Demo Completed ===")
}
// Run demonstration
demonstrateHapticFeedback()