init() { /* ... */ }
init(frame: CGRect, style: UITableViewStyle) { /* ... */ }
let myTableView: UITableView = UITableView(frame: .zero, style: .grouped)
let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 40.0))
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)
用 if let 对可选值进行有值绑定
if let image = UIImage(contentsOfFile: "MyImage.png") {
// loaded the image successfully
} else {
// could not load the image
}
myTextField.textColor = .darkGray
myTextField.text = "Hello world”
myTableView.insertSubview(mySubview, at: 2)
如果你调用的方法是没有参数的,调用时也得加上在点方法后也得加上括号
myTableView.layoutIfNeeded()
var x: Any = "hello" as String
x as? String // String with value "hello"
x as? NSString // NSString with value "hello"
x = "goodbye" as NSString
x as? String // String with value "goodbye"
x as? NSString // NSString with value "goodbye"
let userDefaults = UserDefaults.standard
let lastRefreshDate = userDefaults.object(forKey: "LastRefreshDate") // lastRefreshDate is of type Any?
if let date = lastRefreshDate as? Date {
print("\(date.timeIntervalSinceReferenceDate)")
}
如果你确定类型,可强制解包
let myDate = lastRefreshDate as! Date
let timeInterval = myDate.timeIntervalSinceReferenceDate
如果类型不匹配,就会出现错误
let myDate = lastRefreshDate as! String // Error
var nullableProperty: Any? // 可选值,可空和必有值两种情况
var nonNullProperty: Any // 必有值
var unannotatedProperty: Any! // 未知
func returnsNonNullValue() -> Any // 必有返回值
func takesNonNullParameter(value: Any) // 参数必有值
func returnsNullableValue() -> Any? //可选值的返回值
func takesNullableParameter(value: Any?) 可选值的参数
func returnsUnannotatedValue() -> Any! // 未知返回
func takesUnannotatedParameter(value: Any!) 未知参数
var dates: [Date]
var cachedData: NSCache<AnyObject, NSDiscardableContent>
var supportedLocales: [String: [Locale]]
class List<T: NSCopying> : NSObject {
func listByAppendingItemsInList(otherList: List<T>) -> List<T>
}
class ListContainer : NSObject {
func listOfValues() -> List<NSValue>
}
extension ListContainer {
func listOfObjects() -> List<NSCopying>
}
extension
extension UIBezierPath {
convenience init(triangleSideLength: CGFloat, origin: CGPoint) {
self.init()
let squareRoot = CGFloat(sqrt(3.0))
let altitude = (squareRoot * triangleSideLength) / 2
move(to: origin)
addLine(to: CGPoint(x: origin.x + triangleSideLength, y: origin.y))
addLine(to: CGPoint(x: origin.x + triangleSideLength / 2, y: origin.y + altitude))
close()
}
}
extension CGRect {
var area: CGFloat {
return width * height
}
}
let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area
OC的block,Swift的闭包closures
void (^completionBlock)(NSData *) = ^(NSData *data) {
// ...
}
let completionBlock: (Data) -> Void = { data in
// ...
}
解决循环引用问题的处理
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
};
self.closure = { [unowned self] in
self.doSomething()
}
类定义
class Jukebox: NSObject {
var library: Set<String>
var nowPlaying: String?
var isCurrentlyPlaying: Bool {
return nowPlaying != nil
}
class var favoritesPlaylist: [String] {
// return an array of song names
}
init(songs: String...) {
self.library = Set<String>(songs)
}
func playSong(named name: String) throws {
// play song or throw an error if unavailable
}
}
NOTE
You cannot subclass a Swift class in Objective-C. 你不能用OC来实现一个Swift的子类
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
let action = #selector(MyViewController.tappedButton)
myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
}
func tappedButton(sender: UIButton?) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
let string: NSString = "Hello, Cocoa!"
let selector = #selector(NSString.lowercased(with:))
let locale = Locale.current
if let result = string.perform(selector, with: locale) {
print(result.takeUnretainedValue())
}
// Prints "hello, cocoa!"
let array: NSArray = ["delta", "alpha", "zulu"]
// Not a compile-time error because NSDictionary has this selector.
let selector = #selector(NSDictionary.allKeysForObject)
// Raises an exception because NSArray does not respond to this selector.
array.perform(selector)
@objc(Color) OC能访问得到这个Swift类
@objc(Color)
enum Цвет: Int {
@objc(Red)
case Красный
@objc(Black)
case Черный
}
@objc(Squirrel)
class Белка: NSObject {
@objc(color)
var цвет: Цвет = .Красный
@objc(initWithName:)
init (имя: String) {
// ...
}
@objc(hideNuts:inTree:)
func прячьОрехи(количество: Int, вДереве дерево: Дерево) {
// ...
}
}
class Person: NSObject {
var name: String
var friends: [Person] = []
var bestFriend: Person? = nil
init(name: String) {
self.name = name
}
}
let gabrielle = Person(name: "Gabrielle")
let jim = Person(name: "Jim")
let yuanyuan = Person(name: "Yuanyuan")
gabrielle.friends = [jim, yuanyuan]
gabrielle.bestFriend = yuanyuan
#keyPath(Person.name)
// "name"
gabrielle.value(forKey: #keyPath(Person.name))
// "Gabrielle"
#keyPath(Person.bestFriend.name)
// "bestFriend.name"
gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))
// "Yuanyuan"
#keyPath(Person.friends.name)
// "friends.name"
gabrielle.value(forKeyPath: #keyPath(Person.friends.name))
// ["Yuanyuan", “Jim”]
用Swift来定义一个OC类的子类
import UIKit
class MySwiftViewController: UIViewController {
// define the class
}
遵守协议
class MySwiftViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// define the class
}
let myPersonClass: AnyClass? = NSClassFromString("MyGreatApp.Person”)
托线操作
class MyViewController: UIViewController {
// 属性托线
@IBOutlet weak var button: UIButton!
@IBOutlet var textFields: [UITextField]!
// 事件托线
@IBAction func buttonTapped(sender: AnyObject) {
print("button tapped!")
}
}
IB可视化操作,实践了下感觉如果电脑反应不快,会卡得慌,于是就没有用了,不过很是方便
@IBDesignable
class MyCustomView: UIView {
@IBInspectable var textColor: UIColor
@IBInspectable var iconHeight: CGFloat
// ...
}
定义协议
import UIKit
@objc protocol MyCustomProtocol {
var people: [Person] { get }
func tableView(_ tableView: UITableView, configure cell: UITableViewCell, forPerson person: Person)
@objc optional func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forPerson person: Person)
}
OC对象也能遵守实现这个协议
@interface MyCustomController: UIViewController <MyCustomProtocol>
@property (nonatomic, strong) NSArray<Person *> *people;
@end
@implementation MyCustomController
@synthesize people;
- (void)tableView:(UITableView *)tableView
configure:(UITableViewCell *)cell
forPerson:(Person *)person
{
// Configure cell
}
@end
与Cocoa Frameworks进行操作
import Foundation
let string: String = "abc"
let bridgedString: NSString = string as NSString
let stringLiteral: NSString = "123"
if let integerValue = Int(stringLiteral as String) {
print("\(stringLiteral) is the integer \(integerValue)")
}
// Prints "123 is the integer 123"
import Foundation
let number = 42
let bridgedNumber: NSNumber = number as NSNumber
let integerLiteral: NSNumber = 5
let floatLiteral: NSNumber = 3.14159
let booleanLiteral: NSNumber = true
lazy loading
直接创建的对象
lazy var XML: XMLDocument = try! XMLDocument(contentsOf: Bundle.main.url(forResource: "document", withExtension: "xml")!, options: 0)
var pattern: String
lazy var regex: NSRegularExpression = try! NSRegularExpression(pattern: self.pattern, options: [])
创建完一个对象,还需要对它进行特别属性设置的时候,这样写
lazy var currencyFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "¤"
return formatter
}()
NOTE
假如这个属性还没有加载,并且被多个线程同时访问,那么不能保证这个属性真的只初始化一次
对于 异常的处理
let fileManager = FileManager.default
let fromURL = URL(fileURLWithPath: "/path/to/old")
let toURL = URL(fileURLWithPath: "/path/to/new")
do {
try fileManager.moveItem(at: fromURL, to: toURL)
} catch let error as NSError {
print("Error: \(error.domain)")
}
do {
try fileManager.moveItem(at: fromURL, to: toURL)
} catch CocoaError.fileNoSuchFile {
print("Error: no such file exists")
} catch CocoaError.fileReadUnsupportedScheme {
print("Error: unsupported scheme (should be 'file://')")
}
代码对比,精简了很多下面
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *tmpURL = [fileManager URLForDirectory:NSCachesDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:nil];
if (tmpURL != nil) {
// ...
}
let fileManager = FileManager.default
if let tmpURL = try? fileManager.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) {
// ...
}
KVO
使用关键字 dynamic 字来修饰你想要监听变化的这个属性
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
写一个全局的变量来记录对比操作
private var myContext = 0
在需要开启监听的地方监听,然后重写这个方法 observeValue(for:of:change:context:)
还有一点很重要,对象销毁时在方法 deinit移除监听
class MyObserver: NSObject {
var objectToObserve = MyObjectToObserve()
override init() {
super.init()
objectToObserve.addObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate), options: .new, context: &myContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &myContext {
if let newValue = change?[.newKey] {
print("Date changed: \(newValue)")
}
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
deinit {
objectToObserve.removeObserver(self, forKeyPath: #keyPath(MyObjectToObserve.myDate), context: &myContext)
}
}
单例的写法
class Singleton {
static let sharedInstance = Singleton()
}
如果你需要做些额外的事情 ,可以还这样写
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
对于 OC isKindOfClass还有confirmsToProtocal可以用is as?来处理
if object is UIButton {
// object is of type UIButton
} else {
// object is not of type UIButton
}
if let button = object as? UIButton {
// object is successfully cast to type UIButton and bound to button
} else {
// object could not be cast to type UIButton
}
if let dataSource = object as? UITableViewDataSource {
// object conforms to UITableViewDataSource and is bound to dataSource
} else {
// object not conform to UITableViewDataSource
}
自动释放池的运用
import Foundation
autoreleasepool {
// code that creates autoreleased objects.
}
方法可用性的检测
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
// Method is available for use.
} else {
// Method is not available.
}
let locationManager = CLLocationManager()
if #available(iOS 8.0, macOS 10.10, *) {
locationManager.requestWhenInUseAuthorization()
}
let locationManager = CLLocationManager()
guard #available(iOS 8.0, macOS 10.10, *) else { return }
locationManager.requestWhenInUseAuthorization()
你也可以定义一个特别的方法在特别的版下特别的平台下运行
@available(iOS 8.0, macOS 10.10, *)
func useShinyNewFeature() {
// ...
}
条件编译
#if DEBUG_LOGGING
print("Flag enabled.")
#endif
#if arch(arm) || arch(arm64)
#if swift(>=3.0)
print("Using Swift 3 ARM code")
#else
print("Using Swift 2.2 ARM code")
#endif
#elseif arch(x86_64)
print("Using 64-bit x86 code.")
#else
print("Using general code.")
#endif