Open popeyelau opened 5 years ago
extension Bundle {
var appName: String {
return infoDictionary?["CFBundleName"] as! String
}
var bundleId: String {
return bundleIdentifier!
}
var versionNumber: String {
return infoDictionary?["CFBundleShortVersionString"] as! String
}
var buildNumber: String {
return infoDictionary?["CFBundleVersion"] as! String
}
}
// Builder allows you to create an instance and setting it up in a simple way:
protocol Builder {}
extension Builder {
public func with(configure: (inout Self) -> Void) -> Self {
var this = self
configure(&this)
return this
}
}
// We need NSObject to conform to Builder to enable it for all subclasses of it 😊
extension NSObject: Builder {}
private let tableView = UITableView(frame: .zero, style: .plain).with { tableView in
tableView.backgroundColor = .white
tableView.separatorColor = .darkGray
tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 10.0, right: 0)
tableView.allowsMultipleSelection = true
}
extension UIView {
func addSubviews(_ subviews: UIView...) {
subviews.forEach(addSubview)
}
}
// Add multiple subviews in a single line
view.addSubviews(imageView, slider, view, label)
// Class Name Extension
protocol ClassNameProtocol {
static var className: String { get }
var className: String { get }
}
extension ClassNameProtocol { static var className: String { return String(describing: self) }
var className: String {
return type(of: self).className
}
}
extension NSObject: ClassNameProtocol {}
UIView.className // "UIView" UILabel().className // "UILabel"
nil
// Use compactMap function to receive an array of nonoptional values
// when your transformation produces an optional value.
let possibleNumbers = ["1", "2", "three", "///4///", "5", "Fish"]
let mapped: [Int?] = possibleNumbers.map { Int($0) }
// [1, 2, nil, nil, 5, nil]
let compactMapped: [Int] = possibleNumbers.compactMap { Int($0) }
// [1, 2, 5]
extension Bundle {
func decode<T: Decodable>(_ type: T.Type, from filename: String) -> T {
guard let json = url(forResource: filename, withExtension: nil) else {
fatalError("Failed to locate \(filename) in app bundle.")
}
guard let jsonData = try? Data(contentsOf: json) else {
fatalError("Failed to load \(filename) from app bundle.")
}
let decoder = JSONDecoder()
guard let result = try? decoder.decode(T.self, from: jsonData) else {
fatalError("Failed to decode \(filename) from app bundle.")
}
return result
}
}
let items = Bundle.main.decode([ResponseItem].self, from: "Response.json")
let dispatchGroup = DispatchGroup()
dispatchGroup.enter() task1 { dispatchGroup.leave() }
dispatchGroup.enter() task2 { dispatchGroup.leave() }
dispatchGroup.notify(queue: .main) { //done }
distinct(by:)
public extension Sequence {
/// Returns a sequence that contains no duplicate entries according to the
/// generic hash and equality comparisons on the keys returned by the given
/// key-generating block. If an element occurs multiple times in the sequence
/// then the later occurrences are discarded.
///
/// - Parameter keyBlock: Key generating block.
public func distinct<Key: Hashable>(by keyBlock: (Iterator.Element) -> Key) -> [Iterator.Element] {
var seen: [Key: Bool] = [:]
return self.filter {
seen.updateValue(true, forKey: keyBlock($0)) == nil
}
}
}
struct User: CustomStringConvertible {
let id: Int
var description: String {
return "User \(id)"
}
}
let users = [User(id: 1), User(id: 1), User(id: 2)]
print(users.distinct { $0.id }) //[User 1, User 2]
Remove element by the instances in an array
public extension Array where Element: Equatable {
@discardableResult
public mutating func remove(element: Element) -> Index? {
guard let index = index(of: element) else { return nil }
remove(at: index)
return index
}
@discardableResult
public mutating func remove(elements: [Element]) -> [Index] {
return elements.flatMap { remove(element: $0) }
}
}
let array = ["foo", "bar"] array.remove(element: "foo") array // ["bar"]
public extension UIWindow {
/// SwifterSwift: Switch current root view controller with a new view controller.
///
/// - Parameters:
/// - viewController: new view controller.
/// - animated: set to true to animate view controller change (default is true).
/// - duration: animation duration in seconds (default is 0.5).
/// - options: animation options (default is .transitionFlipFromRight).
/// - completion: optional completion handler called after view controller is changed.
public func switchRootViewController(
to viewController: UIViewController,
animated: Bool = true,
duration: TimeInterval = 0.5,
options: UIView.AnimationOptions = .transitionFlipFromRight,
_ completion: (() -> Void)? = nil) {
guard animated else {
rootViewController = viewController
completion?()
return
}
UIView.transition(with: self, duration: duration, options: options, animations: {
let oldState = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
self.rootViewController = viewController
UIView.setAnimationsEnabled(oldState)
}, completion: { _ in
completion?()
})
}
}
import Foundation
struct Response<T: Decodable>: Decodable{
let code: Int
let msg: String
let data: T
}
struct User: Decodable {
let name: String
let bio: String
}
let json = """
{
"code": 200,
"msg": "hello world",
"data": {
"name": "Popeye",
"bio": "五行缺脑"
}
}
"""
let data = Data(json.utf8)
let decoder = JSONDecoder()
if let user = try? decoder.decode(Response<User>.self, from: data).data {
print(user.name, user.bio) //Popeye 五行缺脑
}
通过实现init(from decoder:)
方法自定义解析过程
struct PagedResponse<T: Decodable>: Decodable {
let code: Int
let message: String
let page: Int
let total: Int
let data: [T]?
enum CodingKeys: String, CodingKey {
case code
case message
case data
}
enum SubCodingKeys: String, CodingKey {
case data
case page
case total
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
code = try container.decode(Int.self, forKey: .code)
message = try container.decode(String.self, forKey: .message)
let nestedContainer = try container.nestedContainer(keyedBy: SubCodingKeys.self, forKey: .data)
data = try nestedContainer.decodeIfPresent([T].self, forKey: .data)
page = try nestedContainer.decode(Int.self, forKey: .page)
total = try nestedContainer.decode(Int.self, forKey: .total)
}
}
struct Item: Decodable {
let title: String
let key: String
}
let json = """
{
"code": 200,
"message": "success",
"data": {
"data": [{
"title" : "title1",
"key": "key1"
},
{
"title" : "title2",
"key": "key2"
},
{
"title" : "title3",
"key": "key3"
}],
"page": 1,
"total": 3
}
}
"""
let data = Data(json.utf8)
let decoder = JSONDecoder()
guard let resp = try? decoder.decode(PagedResponse<Item>.self, from: data) else {
fatalError()
}
print(resp.code, resp.message, resp.page, resp.total)
if let items = resp.data {
items.forEach { print($0.title, $0.key) }
}
/*
200 success 1 3
title1 key1
title1 key1
title1 key1
*/
About Codable
Codable
协议, 扁平化 json 解码struct Popeye: Codable {
let name: String
let bio: String
let github: String
let telegram: String
let luckNumbers: [Int]
enum CodingKeys: String, CodingKey {
case name
case meta
}
enum SubCodingKeys: String, CodingKey {
case bio
case github
case telegram
case luckNumbers = "numbers"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let name = try container.decode(String.self, forKey: .name)
let nestedContainer = try container.nestedContainer(keyedBy: SubCodingKeys.self, forKey: .meta)
let bio = try nestedContainer.decode(String.self, forKey: .bio)
let github = try nestedContainer.decode(String.self, forKey: .github)
let telegram = try nestedContainer.decode(String.self, forKey: .telegram)
//数组 nestedUnkeyedContainer
var numbers: [Int] = []
var nestedUnkeyedContainer = try nestedContainer.nestedUnkeyedContainer(forKey: .luckNumbers)
while !nestedUnkeyedContainer.isAtEnd {
let number = try nestedUnkeyedContainer.decode(Int.self)
numbers.append(number)
}
// call constructor
self.name = name
self.bio = bio
self.github = github
self.telegram = telegram
self.luckNumbers = numbers
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
var nestedContainer = container.nestedContainer(keyedBy: SubCodingKeys.self, forKey: .meta)
try nestedContainer.encode(bio, forKey: .bio)
try nestedContainer.encode(github, forKey: .github)
try nestedContainer.encode(telegram, forKey: .telegram)
var nestedUnkeyedContainer = nestedContainer.nestedUnkeyedContainer(forKey: .luckNumbers)
try luckNumbers.forEach {
try nestedUnkeyedContainer.encode($0)
}
}
}
let json = """
{
"name" : "Popeye",
"meta": {
"bio": "五行缺脑",
"github": "https://github.com/popeyelau",
"telegram": "https://t.me/PopeyeLau",
"numbers": [1,2,3,4,5]
}
}
"""
let data = Data(json.utf8)
let decoder = JSONDecoder()
guard let popeye = try? decoder.decode(Popeye.self, from: data) else {
fatalError()
}
print(popeye)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
if let data = try? encoder.encode(popeye),
let prettyJson = String(bytes: data, encoding: .utf8) {
print(prettyJson)
}
/*Output:
Popeye(name: "Popeye", bio: "五行缺脑", github: "https://github.com/popeyelau", telegram: "https://t.me/PopeyeLau", luckNumbers: [1, 2, 3, 4, 5])
{
"name" : "Popeye",
"meta" : {
"github" : "https:\/\/github.com\/popeyelau",
"telegram" : "https:\/\/t.me\/PopeyeLau",
"numbers" : [
1,
2,
3,
4,
5
],
"bio" : "五行缺脑"
}
}
*/