如何在 iOS 中模拟不同的外形尺寸?
How to Simulate different form-factors in iOS?
通常,我想针对不同的设备测试我的 iOS-App。由于我没有钱购买所有设备,所以我使用模拟器来购买:)
通常,代码看起来会因 Apple 产品的不同外形而略有不同。因此,我提出了以下开关盒(见下文...)以编程方式区分设备。
switch-case 对于实际的硬件设备工作得很好 - 但它仍然是使用模拟器的一个糟糕的解决方案。
模拟器是它自己的设备!如果我更改为具有不同外形尺寸的模拟器目标,我需要在每个开关案例中 uncomment/comment!
是否有更好的解决方案以编程方式更好地照顾模拟器及其外形尺寸?
switch UIDevice.current.modelName {
// Here there is still the need to uncomment/comment the Devices.Simulator
// for any new form-factor that is being simulated....
// as an example: If simulating an iPhone-8S then the Devices.Simulator needs to be uncommented in the according switch-case...
case Devices.IPhone5, Devices.IPhone5S, Devices.IPhone5C: //, Devices.Simulator:
print("do whatever...")
case Devices.IPhone6, Devices.IPhone6S, Devices.IPhone7, Devices.IPhone8: //, Devices.Simulator:
print("do whatever...")
case Devices.IPhone6Plus, Devices.IPhone6SPlus, Devices.IPhone7Plus, Devices.IPhone8Plus, Devices.Simulator:
print("do whatever...")
case Devices.IPhoneX: //, Devices.Simulator:
print("do whatever...")
default:
print("do whatever...")
}
当然,在您的代码库中有以下内容:
public enum Devices: String {
case IPodTouch5
case IPodTouch6
case IPhone4
case IPhone4S
case IPhone5
case IPhone5C
case IPhone5S
case IPhone6
case IPhone6Plus
case IPhone6S
case IPhone6SPlus
case IPhone7
case IPhone7Plus
case IPhoneSE
case IPhone8
case IPhone8Plus
case IPhoneX
case IPad2
case IPad3
case IPad4
case IPad5
case IPadAir
case IPadAir2
case IPadMini
case IPadMini2
case IPadMini3
case IPadMini4
case IPadPro_9_7
case IPadPro_12_9
case IPadPro_12_9_2ndGen
case IPadPro_10_5
case AppleTV_5_3
case AppleTV_6_2
case HomePod
case Simulator
case Other
}
还有...
public extension UIDevice {
public var modelName: Devices {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
switch identifier {
case "iPod5,1": return Devices.IPodTouch5
case "iPod7,1": return Devices.IPodTouch6
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return Devices.IPhone4
case "iPhone4,1": return Devices.IPhone4S
case "iPhone5,1", "iPhone5,2": return Devices.IPhone5
case "iPhone5,3", "iPhone5,4": return Devices.IPhone5C
case "iPhone6,1", "iPhone6,2": return Devices.IPhone5S
case "iPhone7,2": return Devices.IPhone6
case "iPhone7,1": return Devices.IPhone6Plus
case "iPhone8,1": return Devices.IPhone6S
case "iPhone8,2": return Devices.IPhone6SPlus
case "iPhone9,1", "iPhone9,3": return Devices.IPhone7
case "iPhone9,2", "iPhone9,4": return Devices.IPhone7Plus
case "iPhone8,4": return Devices.IPhoneSE
case "iPhone10,1", "iPhone10,4": return Devices.IPhone8
case "iPhone10,2", "iPhone10,5": return Devices.IPhone8Plus
case "iPhone10,3", "iPhone10,6": return Devices.IPhoneX
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
case "iPad3,1", "iPad3,2", "iPad3,3": return Devices.IPad3
case "iPad3,4", "iPad3,5", "iPad3,6": return Devices.IPad4
case "iPad4,1", "iPad4,2", "iPad4,3": return Devices.IPadAir
case "iPad5,3", "iPad5,4": return Devices.IPadAir2
case "iPad6,11", "iPad6,12": return Devices.IPad5
case "iPad2,5", "iPad2,6", "iPad2,7": return Devices.IPadMini
case "iPad4,4", "iPad4,5", "iPad4,6": return Devices.IPadMini2
case "iPad4,7", "iPad4,8", "iPad4,9": return Devices.IPadMini3
case "iPad5,1", "iPad5,2": return Devices.IPadMini4
case "iPad6,3", "iPad6,4": return Devices.IPadPro_9_7
case "iPad6,7", "iPad6,8": return Devices.IPadPro_12_9
case "iPad7,1", "iPad7,2": return Devices.IPadPro_12_9_2ndGen
case "iPad7,3", "iPad7,4": return Devices.IPadPro_10_5
case "AppleTV5,3": return Devices.AppleTV_5_3
case "AppleTV6,2": return Devices.AppleTV_6_2
case "AudioAccessory1,1": return Devices.HomePod
case "i386", "x86_64": return Devices.Simulator
default: return Devices.Other
}
}
}
我找到了更好的解决方案,请参阅 "With the input from Martin R,...."
根据 Martin R 的输入,我现在有了一个很好的解决方案,用户在区分 iOS-设备的外形尺寸时无需在代码中手动输入内容(无论是硬件还是模拟器)! [当然,未来新的 Apple 设备除外...]
最重要的是:它也是将 iPhoneSE 与 iPhone6/7/8 外形尺寸区分开来的解决方案!
struct AppConstants {
// feature flags
struct FEATUREFLAG {
static let DEVICE_MODEL_NAME = { () -> Devices in
switch UIDevice.current.modelName {
case Devices.Simulator:
// set featureFlag for different form-factors to be simulated...
return UIDevice.current.simulatorModelName
default:
// set featureFlag for different form-factors on actual device...
return UIDevice.current.modelName
}
}()
}
}
以及设备扩展中的更改:
public extension UIDevice {
public var modelName: Devices {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return self.getDeviceFromIdentifier(identifier: identifier)
}
public var simulatorModelName: Devices {
if let simulatorModelIdentifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { return getDeviceFromIdentifier(identifier: simulatorModelIdentifier) }
var sysinfo = utsname()
uname(&sysinfo) // ignore return value
return getDeviceFromIdentifier(identifier: String(bytes: Data(bytes: &sysinfo.machine, count: Int(_SYS_NAMELEN)), encoding: .ascii)!.trimmingCharacters(in: .controlCharacters))
}
private func getDeviceFromIdentifier(identifier: String) -> Devices {
switch identifier {
case "iPod5,1": return Devices.IPodTouch5
case "iPod7,1": return Devices.IPodTouch6
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return Devices.IPhone4
case "iPhone4,1": return Devices.IPhone4S
case "iPhone5,1", "iPhone5,2": return Devices.IPhone5
case "iPhone5,3", "iPhone5,4": return Devices.IPhone5C
case "iPhone6,1", "iPhone6,2": return Devices.IPhone5S
case "iPhone7,2": return Devices.IPhone6
case "iPhone7,1": return Devices.IPhone6Plus
case "iPhone8,1": return Devices.IPhone6S
case "iPhone8,2": return Devices.IPhone6SPlus
case "iPhone9,1", "iPhone9,3": return Devices.IPhone7
case "iPhone9,2", "iPhone9,4": return Devices.IPhone7Plus
case "iPhone8,4": return Devices.IPhoneSE
case "iPhone10,1", "iPhone10,4": return Devices.IPhone8
case "iPhone10,2", "iPhone10,5": return Devices.IPhone8Plus
case "iPhone10,3", "iPhone10,6": return Devices.IPhoneX
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
case "iPad3,1", "iPad3,2", "iPad3,3": return Devices.IPad3
case "iPad3,4", "iPad3,5", "iPad3,6": return Devices.IPad4
case "iPad4,1", "iPad4,2", "iPad4,3": return Devices.IPadAir
case "iPad5,3", "iPad5,4": return Devices.IPadAir2
case "iPad6,11", "iPad6,12": return Devices.IPad5
case "iPad2,5", "iPad2,6", "iPad2,7": return Devices.IPadMini
case "iPad4,4", "iPad4,5", "iPad4,6": return Devices.IPadMini2
case "iPad4,7", "iPad4,8", "iPad4,9": return Devices.IPadMini3
case "iPad5,1", "iPad5,2": return Devices.IPadMini4
case "iPad6,3", "iPad6,4": return Devices.IPadPro_9_7
case "iPad6,7", "iPad6,8": return Devices.IPadPro_12_9
case "iPad7,1", "iPad7,2": return Devices.IPadPro_12_9_2ndGen
case "iPad7,3", "iPad7,4": return Devices.IPadPro_10_5
case "AppleTV5,3": return Devices.AppleTV_5_3
case "AppleTV6,2": return Devices.AppleTV_6_2
case "AudioAccessory1,1": return Devices.HomePod
case "i386", "x86_64": return Devices.Simulator
default: return Devices.Other
}
}
}
并且:
public enum Devices: String {
case IPodTouch5
case IPodTouch6
case IPhone4
case IPhone4S
case IPhone5
case IPhone5C
case IPhone5S
case IPhone6
case IPhone6Plus
case IPhone6S
case IPhone6SPlus
case IPhone7
case IPhone7Plus
case IPhoneSE
case IPhone8
case IPhone8Plus
case IPhoneX
case IPad2
case IPad3
case IPad4
case IPad5
case IPadAir
case IPadAir2
case IPadMini
case IPadMini2
case IPadMini3
case IPadMini4
case IPadPro_9_7
case IPadPro_12_9
case IPadPro_12_9_2ndGen
case IPadPro_10_5
case AppleTV_5_3
case AppleTV_6_2
case HomePod
case Simulator
case Other
}
通常,我想针对不同的设备测试我的 iOS-App。由于我没有钱购买所有设备,所以我使用模拟器来购买:)
通常,代码看起来会因 Apple 产品的不同外形而略有不同。因此,我提出了以下开关盒(见下文...)以编程方式区分设备。
switch-case 对于实际的硬件设备工作得很好 - 但它仍然是使用模拟器的一个糟糕的解决方案。
模拟器是它自己的设备!如果我更改为具有不同外形尺寸的模拟器目标,我需要在每个开关案例中 uncomment/comment!
是否有更好的解决方案以编程方式更好地照顾模拟器及其外形尺寸?
switch UIDevice.current.modelName {
// Here there is still the need to uncomment/comment the Devices.Simulator
// for any new form-factor that is being simulated....
// as an example: If simulating an iPhone-8S then the Devices.Simulator needs to be uncommented in the according switch-case...
case Devices.IPhone5, Devices.IPhone5S, Devices.IPhone5C: //, Devices.Simulator:
print("do whatever...")
case Devices.IPhone6, Devices.IPhone6S, Devices.IPhone7, Devices.IPhone8: //, Devices.Simulator:
print("do whatever...")
case Devices.IPhone6Plus, Devices.IPhone6SPlus, Devices.IPhone7Plus, Devices.IPhone8Plus, Devices.Simulator:
print("do whatever...")
case Devices.IPhoneX: //, Devices.Simulator:
print("do whatever...")
default:
print("do whatever...")
}
当然,在您的代码库中有以下内容:
public enum Devices: String {
case IPodTouch5
case IPodTouch6
case IPhone4
case IPhone4S
case IPhone5
case IPhone5C
case IPhone5S
case IPhone6
case IPhone6Plus
case IPhone6S
case IPhone6SPlus
case IPhone7
case IPhone7Plus
case IPhoneSE
case IPhone8
case IPhone8Plus
case IPhoneX
case IPad2
case IPad3
case IPad4
case IPad5
case IPadAir
case IPadAir2
case IPadMini
case IPadMini2
case IPadMini3
case IPadMini4
case IPadPro_9_7
case IPadPro_12_9
case IPadPro_12_9_2ndGen
case IPadPro_10_5
case AppleTV_5_3
case AppleTV_6_2
case HomePod
case Simulator
case Other
}
还有...
public extension UIDevice {
public var modelName: Devices {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
switch identifier {
case "iPod5,1": return Devices.IPodTouch5
case "iPod7,1": return Devices.IPodTouch6
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return Devices.IPhone4
case "iPhone4,1": return Devices.IPhone4S
case "iPhone5,1", "iPhone5,2": return Devices.IPhone5
case "iPhone5,3", "iPhone5,4": return Devices.IPhone5C
case "iPhone6,1", "iPhone6,2": return Devices.IPhone5S
case "iPhone7,2": return Devices.IPhone6
case "iPhone7,1": return Devices.IPhone6Plus
case "iPhone8,1": return Devices.IPhone6S
case "iPhone8,2": return Devices.IPhone6SPlus
case "iPhone9,1", "iPhone9,3": return Devices.IPhone7
case "iPhone9,2", "iPhone9,4": return Devices.IPhone7Plus
case "iPhone8,4": return Devices.IPhoneSE
case "iPhone10,1", "iPhone10,4": return Devices.IPhone8
case "iPhone10,2", "iPhone10,5": return Devices.IPhone8Plus
case "iPhone10,3", "iPhone10,6": return Devices.IPhoneX
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
case "iPad3,1", "iPad3,2", "iPad3,3": return Devices.IPad3
case "iPad3,4", "iPad3,5", "iPad3,6": return Devices.IPad4
case "iPad4,1", "iPad4,2", "iPad4,3": return Devices.IPadAir
case "iPad5,3", "iPad5,4": return Devices.IPadAir2
case "iPad6,11", "iPad6,12": return Devices.IPad5
case "iPad2,5", "iPad2,6", "iPad2,7": return Devices.IPadMini
case "iPad4,4", "iPad4,5", "iPad4,6": return Devices.IPadMini2
case "iPad4,7", "iPad4,8", "iPad4,9": return Devices.IPadMini3
case "iPad5,1", "iPad5,2": return Devices.IPadMini4
case "iPad6,3", "iPad6,4": return Devices.IPadPro_9_7
case "iPad6,7", "iPad6,8": return Devices.IPadPro_12_9
case "iPad7,1", "iPad7,2": return Devices.IPadPro_12_9_2ndGen
case "iPad7,3", "iPad7,4": return Devices.IPadPro_10_5
case "AppleTV5,3": return Devices.AppleTV_5_3
case "AppleTV6,2": return Devices.AppleTV_6_2
case "AudioAccessory1,1": return Devices.HomePod
case "i386", "x86_64": return Devices.Simulator
default: return Devices.Other
}
}
}
我找到了更好的解决方案,请参阅 "With the input from Martin R,...."
根据 Martin R 的输入,我现在有了一个很好的解决方案,用户在区分 iOS-设备的外形尺寸时无需在代码中手动输入内容(无论是硬件还是模拟器)! [当然,未来新的 Apple 设备除外...]
最重要的是:它也是将 iPhoneSE 与 iPhone6/7/8 外形尺寸区分开来的解决方案!
struct AppConstants {
// feature flags
struct FEATUREFLAG {
static let DEVICE_MODEL_NAME = { () -> Devices in
switch UIDevice.current.modelName {
case Devices.Simulator:
// set featureFlag for different form-factors to be simulated...
return UIDevice.current.simulatorModelName
default:
// set featureFlag for different form-factors on actual device...
return UIDevice.current.modelName
}
}()
}
}
以及设备扩展中的更改:
public extension UIDevice {
public var modelName: Devices {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return self.getDeviceFromIdentifier(identifier: identifier)
}
public var simulatorModelName: Devices {
if let simulatorModelIdentifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { return getDeviceFromIdentifier(identifier: simulatorModelIdentifier) }
var sysinfo = utsname()
uname(&sysinfo) // ignore return value
return getDeviceFromIdentifier(identifier: String(bytes: Data(bytes: &sysinfo.machine, count: Int(_SYS_NAMELEN)), encoding: .ascii)!.trimmingCharacters(in: .controlCharacters))
}
private func getDeviceFromIdentifier(identifier: String) -> Devices {
switch identifier {
case "iPod5,1": return Devices.IPodTouch5
case "iPod7,1": return Devices.IPodTouch6
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return Devices.IPhone4
case "iPhone4,1": return Devices.IPhone4S
case "iPhone5,1", "iPhone5,2": return Devices.IPhone5
case "iPhone5,3", "iPhone5,4": return Devices.IPhone5C
case "iPhone6,1", "iPhone6,2": return Devices.IPhone5S
case "iPhone7,2": return Devices.IPhone6
case "iPhone7,1": return Devices.IPhone6Plus
case "iPhone8,1": return Devices.IPhone6S
case "iPhone8,2": return Devices.IPhone6SPlus
case "iPhone9,1", "iPhone9,3": return Devices.IPhone7
case "iPhone9,2", "iPhone9,4": return Devices.IPhone7Plus
case "iPhone8,4": return Devices.IPhoneSE
case "iPhone10,1", "iPhone10,4": return Devices.IPhone8
case "iPhone10,2", "iPhone10,5": return Devices.IPhone8Plus
case "iPhone10,3", "iPhone10,6": return Devices.IPhoneX
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
case "iPad3,1", "iPad3,2", "iPad3,3": return Devices.IPad3
case "iPad3,4", "iPad3,5", "iPad3,6": return Devices.IPad4
case "iPad4,1", "iPad4,2", "iPad4,3": return Devices.IPadAir
case "iPad5,3", "iPad5,4": return Devices.IPadAir2
case "iPad6,11", "iPad6,12": return Devices.IPad5
case "iPad2,5", "iPad2,6", "iPad2,7": return Devices.IPadMini
case "iPad4,4", "iPad4,5", "iPad4,6": return Devices.IPadMini2
case "iPad4,7", "iPad4,8", "iPad4,9": return Devices.IPadMini3
case "iPad5,1", "iPad5,2": return Devices.IPadMini4
case "iPad6,3", "iPad6,4": return Devices.IPadPro_9_7
case "iPad6,7", "iPad6,8": return Devices.IPadPro_12_9
case "iPad7,1", "iPad7,2": return Devices.IPadPro_12_9_2ndGen
case "iPad7,3", "iPad7,4": return Devices.IPadPro_10_5
case "AppleTV5,3": return Devices.AppleTV_5_3
case "AppleTV6,2": return Devices.AppleTV_6_2
case "AudioAccessory1,1": return Devices.HomePod
case "i386", "x86_64": return Devices.Simulator
default: return Devices.Other
}
}
}
并且:
public enum Devices: String {
case IPodTouch5
case IPodTouch6
case IPhone4
case IPhone4S
case IPhone5
case IPhone5C
case IPhone5S
case IPhone6
case IPhone6Plus
case IPhone6S
case IPhone6SPlus
case IPhone7
case IPhone7Plus
case IPhoneSE
case IPhone8
case IPhone8Plus
case IPhoneX
case IPad2
case IPad3
case IPad4
case IPad5
case IPadAir
case IPadAir2
case IPadMini
case IPadMini2
case IPadMini3
case IPadMini4
case IPadPro_9_7
case IPadPro_12_9
case IPadPro_12_9_2ndGen
case IPadPro_10_5
case AppleTV_5_3
case AppleTV_6_2
case HomePod
case Simulator
case Other
}