The Swift Programming Language (Swift 3.1)
- Swift中文件权限
fileprivate :如名字一样,只有这个文件才能访问
private: 只能在作用域访问
interal: 默认,在整个模块可以访问.
public: 在同一个模块里面可以继承或者重写,在模块外可以访问,但不可以重写和继承
open:在所有模块都可以访问,重写和继承
权限由大到小排序:
open > public > interal > fileprivate > private
- 关键字
final
:
- 可以通过把方法,属性或下标标记为`final`来防止它们被重写,只需要在声明关键字前加上`final`修饰符即可(例如:`final var`,`final func`,`final class func`,以及`final subscript`)
- 可以通过在关键字`class`前添加`final`修饰符(`final class`)来将整个类标记为 `final` 的。这样的类是不可被继承的,试图继承这样的类会导致编译报错。
staic
: 在方法的func
关键字之前加上关键字static
,来指定类型方法。类还可以用关键字class
来允许子类重写父类的方法实现。
- Swift调用OC代码
1.在Swift项目中创建OC文件时,Xcode会提示是否需要创建桥接文件,点击创建桥接文件,会生成“工程名-Bridging-Header.h”文(也可手动创建Header File,命名为XXX-Bridging-Header.h,xxx为工程名称)
2.配置.h文件位置:TARGETS->Build Settings->Swift Compiler->Objective-C Bridging Header,设置路径如工程名为为Demo,则此处可配置为:Demo/Demo-Bridging-Header.h。(前提Demo-Bridging-Header.h在Demo工程根目录下)
3.在XXX-Bridging-Header.h文件中导入OC头文件。如:#import "AFNetworking.h"
- OC调用Swift代码
1.在OC项目中创建Swift文件时,Xcode会提示是否需要创建桥接文件,点击创建桥接文件,会生成“工程名-Bridging-Header.h”文(也可手动创建)
2.配置:TARGETS ->Build Settings -> Packaging ,设置Defines Module为YES,Product Module Name为工程名称(默认为工程的名字)
3.在OC需要用到Swift的文件中导入文件 "Product Module Name-Swift.h", Product Module Name 默认是工程的名字,直接导入#import "工程名-Swift.h"
(注意:导入的是XXX.Swift.h,而不是系统提示的XXX-Bridging-Header.h)
- 声明特性
- 系统版本判断
if #available(iOS 9.0, *) {
if let options = options as? [UIApplicationOpenURLOptionsKey : Any] {
if let sourceAppKey = options[.sourceApplication] {
sourceApplicationKey = (sourceAppKey as? String)!
}
}
} else {
// Fallback on earlier versions
if let options = options as? String {
if options.characters.count > 0 {
sourceApplicationKey = options
}
}
}
- 忽略函数返回值
@discardableResult
func test() -> Bool {
return false
}
- 某个声明已经被重命名
@available(*, unavailable, renamed:"MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
- 平台可用性
@available(iOS 10.0, macOS 10.12, *)
class MyClass {
}
@available(iOS, introduced: 2.0, deprecated: 10.0, message: "Please use openURL:options:completionHandler: instead")
open func openURL(_ url: URL) -> Bool {}
- 使用OC方法调用
以下方法为Swift中定义的方法,若想使用OC方法的命名方式定义,则使用@objc(参数个数需一直),如下:
@objc(beginLogPage:)
public class func beginLogPage(identifier: String) {
}
- 闭包弱引用
- unowned
- 原始实例永远不会为 nil,闭包可以直接使用它,并且直接定义为显式解包可选值。当原始实例被析构后,在闭包中使用这个捕获值将导致崩溃。
- 闭包和捕获对象的生命周期相同,所以对象可以被访问,也就意味着闭包也可以被访问。外部对象和闭包有相同的生命周期,如 `[unowned self]`
- weak:
- 如果捕获原始实例在使用过程中可能为 nil ,必须将引用声明为 weak, 并且在使用之前验证这个引用的有效性。
- 闭包的生命周期和捕获对象的生命周期相互独立,当对象不能再使用时,闭包依然能够被引用。在使用它之前验证一下它是否为 nil(请不要对它进行强制解包).如:
[weak delegate = self.delegate!]
class aClass{
var value = 1
}
var c1 = aClass()
var c2 = aClass()
var fSpec = { [unowned c1, weak c2] in
c1.value += 1
if let c2 = c2 {
c2.value += 1
}
}
fSpec()
print(c1.value,c2.value) //Prints 2 and 2
- 判断字符串是否包含另一字符串
if (strA.components(separatedBy: "strB").count)! > 1 {
println("包含")
} else {
println("不包含")
}
>= iOS iOS 8 NSString方法containsString
let str: String = "123test4"
if (str as NSString).contains("test") {
print("包含")
}
if str.contains("test") {
print("包含")
}
- 方法中修改可变字典、数组等
var pageInfoDic = [String: AnyObject]()
setDic(origin: &pageInfoDic, value: pageInfo.pageIdentifier, key: "PID")
class func setDic(origin dic: inout [String: AnyObject], value: Any?, key: String) {
guard let value = value else {
return
}
if let value = value as? String {
if value == "" {
return
}
}
dic[key] = value as AnyObject?
}
- 解档枚举类型
public enum UserSex: Int {
case EGSexFemale = 0
case EGSexMale
case EGSexUnknown
}
public class EGUserInfo: NSObject,NSCoding {
public var userSex: UserSex = .EGSexUnknown
}
// MARK:- 归档及解档
public func encode(with aCoder: NSCoder) {
aCoder.encode(userSex.rawValue, forKey: "userSex")
}
required public init?(coder aDecoder: NSCoder) {
super.init()
userSex = UserSex(rawValue: aDecoder.decodeInteger(forKey: "userSex"))!
}
- 扩展通知,方便调用
方法1:
// 添加通知
NotificationCenter.default.addObserver(self, selector: #selector(enterForeground(notify:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
// 发送通知
NotificationCenter.default.post(name: NSNotification.Name("foreground"), object: nil)
方法2:
import Foundation
class TestDemo: NSObject {
func testDemo() {
// 添加通知
NotificationCenter.default.addObserver(self, selector: .foregroundNotify, name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}
// MARK: - 通知执行方法
func enterForeground(notify: Notification) -> Void {
print("1111")
}
// MARK: - 析构函数
deinit {
NotificationCenter.default.removeObserver(self)
}
}
// MARK: - Selector 扩展
fileprivate extension Selector {
static let foregroundNotify = #selector(TestDemo.enterForeground(notify:))
}
- GCD
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0/*延迟时长,单位秒*/) {
print("延迟1s执行")
}
// 异步线程
DispatchQueue.global().async {
// 主线程
DispatchQueue.main.async {
}
}
- 只读属性
// 懒加载
lazy var names: NSArray = {
let names = NSArray()
print("只在首次访问输出")
return names
}()
var appVersion: String {
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] {
return version as! String
}
return ""
}
- 可选类型类型转换
var optionStr: String?
optionStr = "123"
// 1.拆包判断
if let str = optionStr as? String {
print("string")
} else {
print("not string")
}
// 2.map
if let string = optionStr.map({ $0 as String }) {
print("map, string")
} else {
print("map, not string")
}
// 3.flatMap
if let string = optionStr.flatMap({ $0 as? String }) {
print("flatMap, string")
} else {
print("flatMap, not string")
}
// 类型嵌套及解包
class func savePolicy(info: AnyObject) {
if let policyInfo = info as? NSDictionary,
let policyDic = policyInfo["policy"] as? NSDictionary,
let failDic = policyDic["fail"] as? NSDictionary
{
}
}
- 处理不等长的数组
let array2 = ["张三","李四","王五","赵六"]
let array1 = [0,1,2,3,4]
for (index, name) in zip(array1, array2) {
print(name)
print(array2[index])
}
for (model, viewController) in zip(models, viewControllers) {
viewController.model = model
}
- extension使用
extension UIView {
func with(backgroundColor: UIColor) -> Self {
self.backgroundColor = backgroundColor
return self
}
func with(cornerRadius: CGFloat) -> Self {
self.layer.cornerRadius = 3
return self
}
}
// 使用
override func viewDidLoad() {
super.viewDidLoad()
let view = UIView(frame: CGRect(x: 30, y: 30, width: 100, height: 100))
.with(backgroundColor: .blue)
.with(cornerRadius: 3)
self.view.addSubview(view)
}
- 代码注释
在OC中使用以下方式可对方法进行分割分类
#pragma mark - 表示方法分割线
但在Swift中需使用以下方法
// MARK: - 表示方法分割线
其他方法
// FIXME: - 在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。
// TODO: - 表示需要实现,但目前还未实现的功能。
当然FIXME和TODO若查找太麻烦,可以让其在编译时报警告,提醒开发者,可能有问题的地方,方法如下:
工程 -> TARGETS -> Build Phases -> + -> New Run Script Phase,添加相应脚本,内容如下:
Swift脚本:
TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"
OC脚本:
KEYWORDS="TODO:|FIXME:|\?\?\?:|\!\!\!:"
find "${SRCROOT}" \( -name "*.h" -or -name "*.m" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | perl -p -e "s/($KEYWORDS)/ warning: \$1/"
重新运行工程后,便会看到相应的警告提示,如下图所示:
- Swift中数组中删除子数组
在OC中NSMutableArray可以使用removeObjectsInArray:方法删除子数组,但在Swift中没有此方法,只能将数组中需要剔除的对象挨个删除
参考How to remove an array of objects from a Swift 2 Array - removeObjectsInArray
// Swift 2
var wordArray = ["Apple", "Carrot", "Peanut Butter"]
wordArray.append("Hummus")
wordArray.insert("Greek Salad", atIndex: 0)
// Find the objects to remove
var wordsToDelete: [String] = [String]()
for word in wordArray {
if word.lowercaseString.characters.contains("p") {
wordsToDelete.append(word)
}
}
// Find the index and remove each object
for word in wordsToDelete {
if let index = wordArray.indexOf(word) {
wordArray.removeAtIndex(index)
}
}
- 打印对象地址
在debug区域输入:
fr v -R 对象名称
结果如下:
(lldb) fr v -R a
(Swift.Array<Swift.Int>) a = {
_buffer = {
_storage = {
rawValue = 0x0000600000079500 {
Swift._ContiguousArrayStorageBase = {
Swift._SwiftNativeNSArrayWithContiguousStorage = {
Swift._SwiftNativeNSArray = {}
}
countAndCapacity = {
_storage = {
count = {
_value = 3
}
_capacityAndFlags = {
_value = 6
}
}
}
}
}
}
}
}
- Range使用
swift中Range<String.Index>非常麻烦,可以将String转为NSString结合NSRange使用
let levels = "ABCDE"
let nsRange = NSMakeRange(1, 4)
let newString = (levels as NSString).replacingCharacters(in: nsRange, with: "AAAA")
print(newString)
- 数组遍历
let arr: NSArray = [1, 2, 3, 4, 5]
for (index, num) in arr.enumerated() {
result += num as! Int
if index == 2 {
break
}
}
print(result)