Swift小知识
2020-08-28 本文已影响0人
91阿生
1. 关于Swift中Protocol
1. 在 Swift 中,Delegate 就是基于 Protocol 实现的。
2. 定义委托时,我们让 protocol 继承自 AnyObject。这是由于,在 Swift 中,这表示这一个协议只能被应用于 class(而不是 struct 和 enum)。
3. 那么为什么不使用 class 和 NSObjectProtocol,而要使用 AnyObject 呢?NSObjectProtocol 来自 Objective-C,在 pure Swift 的项目中并不推荐使用。class 和 AnyObject 并没有什么区别,在 Xcode 中也能达到相同的功能,但是官方还是推荐使用 AnyObject。
2. 关于SnapKit适配 #available(iOS 11.0, *) 刘海适配
make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
3. 是否全面屏(刘海屏) 适配 iOS 13.0+
var cc_isFullScreen: Bool {
if #available(iOS 13, *) {
let scene = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate
guard let unwrappedWindow = scene?.window else {
return false
}
if unwrappedWindow.safeAreaInsets.left > 0 ||
unwrappedWindow.safeAreaInsets.bottom > 0 {
return true
}
} else if #available(iOS 11, *) {
guard let window = UIApplication.shared.delegate?.window, let unwrapped = window else {
return false
}
if unwrapped.safeAreaInsets.left > 0 || unwrapped.safeAreaInsets.bottom > 0 {
return true
}
}
return false
}
4. 关于CGSize转String; String转CGSize
let size = CGSize(width: 200, height: 80)
// CGSize转String
🌰: let sizeString = "\(size)" → (200.0, 80.0)
// String转CGSize
字符串的size格式: {width, height}
🌰: let rsSize = NSCoder.cgSize(for: sizeString) → (200.0, 80.0)
注: NSCoder类, 需注意字符串格式
public class func string(for offset: UIOffset) -> String
public class func cgPoint(for string: String) -> CGPoint
public class func cgVector(for string: String) -> CGVector
public class func cgSize(for string: String) -> CGSize
public class func cgRect(for string: String) -> CGRect
public class func cgAffineTransform(for string: String) -> CGAffineTransform
public class func uiEdgeInsets(for string: String) -> UIEdgeInsets
5. 关于将字面量转换为特定的类型
Swift枚举中支持以下四种关联值类型:
- 整型(Integer)
- 浮点数(Float Point)
- 字符串(String)
- 布尔类型(Boolean)
使用自定义类型作为枚举的值,想要支持别的类型,可以通过实现 StringLiteralConvertible 协议来完成
Swift 3.0之前,字面量协议的名称:
- ArrayLiteralConvertible 数组字面量协议
- BooleanLiteralConvertible 布尔值字面量协议
- DictionaryLiteralConvertible 字典字面量协议
- FloatLiteralConvertible 浮点数字面量协议
- NilLiteralConvertible nil字面量协议
- IntegerLiteralConvertible 整数字面量协议
- StringLiteralConvertible 字符串字面量协议
- ExpressibleByArrayLiteral 数组字面量协议
- ExpressibleByBooleanLiteral 布尔值字面量协议
- ExpressibleByDictionaryLiteral 字典字面量协议
- ExpressibleByFloatLiteral 浮点数字面量协议
- ExpressibleByNilLiteral nil字面量协议
- ExpressibleByIntegerLiteral 整数字面量协议
- ExpressibleByStringLiteral 字符串字面量协议
其中,ExpressibleByStringLiteral 字符串字面量协议还依赖于以下 2 个协议:
ExpressibleByUnicodeScalarLiteral
ExpressibleByExtendedGraphemeClusterLiteral
也就是说,实现 ExpressibleByStringLiteral 协议时,还需要实现其依赖的另外 2 个协议
🌰例子:
// 实现 CGSize 的字符串字面量协议
// NSCoder.cgSize(for: String), 针对CGSize时String的格式是: {width, height}
extension CGSize: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
let size = NSCoder.cgSize(for: value)
self.init(width: size.width, height: size.height)
}
public init(extendedGraphemeClusterLiteral value: String) {
let size = NSCoder.cgSize(for: value)
self.init(width: size.width, height: size.height)
}
public init(unicodeScalarLiteral value: String) {
let size = NSCoder.cgSize(for: value)
self.init(width: size.width, height: size.height)
}
}
enum Devices: CGSize {
case i5 = "{320, 568}" // 设置值需要字符串类型
}
// 获取Devices.i5真实值, 需要访问枚举的是 rawValue 属性; rawValue类型为CGSize
print(Devices.i5.rawValue) → (320.0, 568.0)
针对官方文档连接:
https://developer.apple.com/documentation/foundation/nscoder/1624484-cgsize
4. 关于iOS 15.0+ 列表滚动到导航栏后,导航栏颜色发生变化。禁止导航栏颜色发生变化
全局设置
if #available(iOS 15.0, *) { //UINavigationBarAppearance属性从iOS13开始
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
// 背景色
navBarAppearance.backgroundColor = UIColor.white
self.navigationController?.navigationBar.standardAppearance = navBarAppearance
self.navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
}
5. 关于iOS 11.0+ 禁止有导航栏 scrollView会默认把 scrollview 向下平移一个导航栏高度
if #available(iOS 11.0, *) {
self.scrollView.contentInsetAdjustmentBehavior = .never
} else {
self.automaticallyAdjustsScrollViewInsets = false
}
6. 关于 百度地图SDK组件化 和 BMKLocationKit,Podfile 以及 xxx.podspec的配置
1、在 Podfile 里配置:
#百度地图SDK现在使用的7个framework,为了支持ssl所以还添加了两个.a的静态库,这个时候需要使用如下命令来让cocoapods对静态库支持
pre_install do |installer|
# workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
end
2、依赖 BaiduMapKit、BMKLocationKit时,需要配置的 podspec:
# 依赖百度地图 SDK; 由于 BMKLocationKit 库中没有组件化文件,
# 第一种方式 :自行添加 Modules文件夹 -> 修改 module.modulemap。问题:直接移进去,这样会导致 `pod install` 时可能丢失该文件
# 第二种方式:使用 prepare_command 下载库文件完成时,执行一个脚本
s.dependency 'BaiduMapKit'
s.dependency 'BMKLocationKit'
s.frameworks = "BMKLocationKit", "BaiduMapAPI_Base", "BaiduMapAPI_Map", "BaiduMapAPI_Search", "BaiduMapAPI_Utils", "Accelerate"
s.libraries = "z", "crypto", "ssl", "c++", "sqlite3.0"
# -undefined dynamic_lookup 这个表明了当主工程和framework都包含同一个库时,会优先使用主工程的库。
s.pod_target_xcconfig = {
# 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit ${PODS_ROOT}/BMKLocationKit/framework',
'LIBRARY_SEARCH_PATHS' => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit/thirdlibs',
'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup -ObjC',
'ENABLE_BITCODE' => 'NO'
}
# mkdir:创建目录(文件夹)touch:创建文件
s.prepare_command = <<-EOF
mkdir ../../Pods/BMKLocationKit/framework/BMKLocationKit.framework/Modules
touch ../../Pods/BMKLocationKit/framework/BMKLocationKit.framework/Modules/module.modulemap
cat <<-EOF > ../../Pods/BMKLocationKit/framework/BMKLocationKit.framework/Modules/module.modulemap
framework module BMKLocationKit {
umbrella header "BMKLocationComponent.h"
export *
module * { export * }
}
\EOF
EOF
7、记录 Podfile 相关指令
# as mentioned here https://github.com/react-native-maps/react-native-maps/issues/3597#issuecomment-745026120
#禁用 bitcode
post_install do |installer|
installer.pods_project.targets.each do |target|
# 设置全部target ENABLE_BITCODE = NO
# target.build_configurations.each do |config|
# config.build_settings['ENABLE_BITCODE'] = 'NO'
# end
# target为 TUIChat || TUICore时,设置以下属性
if target.name == 'TUIChat' || target.name == 'TUICore' || target.name == 'TUIConversation'
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
# config.build_settings['MACH_O_TYPE'] = 'Static Library'
# config.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'] = 'YES'
# 'LIBRARY_SEARCH_PATHS' => '$(inherited) $(PODS_ROOT)/TUIChat/TUIChat/VoiceConvert',
# 'OTHER_LDFLAGS' => '$(inherited) -undefined dynamic_lookup -ObjC',
end
end
end
end