DDLog
/// Debug模式日志打印
/// - Parameters:
/// - message: 内容
/// - file: 文件名
/// - function: 方法名
/// - line: 行号
public func DDLog(_ message: Any?..., file: String = #file, function: String = #function, line: Int = #line){
#if DEBUG
let params = message.compactMap{ "\($0)" }.joined(separator: ", ");
let fmt = DateFormatter.format("yyyy-MM-dd HH:mm:ss.SSSSSSZ");
fmt.locale = Locale(identifier: "zh_CN")
let dateStr = fmt.string(from: Date())
print(dateStr, "\((file as NSString).lastPathComponent).\(function)[line \(line)]: \(params)")
#endif
}
UITableViewCell 复用方法
@objc public extension UITableViewCell{
/// [源]自定义 UITableViewCell 获取方法(兼容OC)
static func dequeueReusableCell(_ tableView: UITableView, identifier: String, style: UITableViewCell.CellStyle = .default) -> Self {
var cell = tableView.dequeueReusableCell(withIdentifier: identifier);
if cell == nil {
cell = self.init(style: style, reuseIdentifier: identifier);
}
cell!.selectionStyle = .none
cell!.separatorInset = .zero
cell!.layoutMargins = .zero
cell!.backgroundColor = .white
return cell as! Self;
}
/// [OC简洁方法]自定义 UITableViewCell 获取方法
static func dequeueReusableCell(_ tableView: UITableView) -> Self {
return dequeueReusableCell(tableView, identifier: String(describing: self), style: .default)
}
}
@objc public extension UITableViewHeaderFooterView{
/// [源]自定义 UITableViewHeaderFooterView 获取方法(兼容OC)
static func dequeueReusableHeaderFooterView(_ tableView: UITableView, identifier: String) -> Self {
var view = tableView.dequeueReusableHeaderFooterView(withIdentifier: identifier)
if view == nil {
view = self.init(reuseIdentifier: identifier)
}
return view as! Self;
}
/// [OC简洁方法]自定义 UITableViewHeaderFooterView 获取方法
static func dequeueReusableHeaderFooterView(_ tableView: UITableView) -> Self {
return dequeueReusableHeaderFooterView(tableView, identifier: String(describing: self))
}
}
UICollectionViewCell 复用方法
@objc public extension UICollectionViewCell{
/// [源]自定义 UICollectionViewCell 获取方法(兼容OC)
static func dequeueReusableCell(_ collectionView: UICollectionView, identifier: String, indexPath: IndexPath) -> Self {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
cell.backgroundColor = .white
return cell as! Self
}
/// [OC简洁方法]自定义 UITableViewCell 获取方法
static func dequeueReusableCell(_ collectionView: UICollectionView, indexPath: IndexPath) -> Self {
return dequeueReusableCell(collectionView, identifier: String(describing: self), indexPath: indexPath)
}
}
DateFormatter: 日期,字符串,时间戳的相互转化
@objc public extension DateFormatter{
/// 获取DateFormatter(默认格式)
static func format(_ formatStr: String = kDateFormat) -> DateFormatter {
let dic = Thread.current.threadDictionary;
if let formatter = dic.object(forKey: formatStr) as? DateFormatter {
return formatter
}
let fmt = DateFormatter();
fmt.dateFormat = formatStr;
fmt.locale = .current;
fmt.locale = Locale(identifier: "zh_CN");
fmt.timeZone = formatStr.contains("GMT") ? TimeZone(identifier: "GMT") : TimeZone.current;
dic.setObject(fmt, forKey: formatStr as NSCopying)
return fmt;
}
/// Date -> String
static func stringFromDate(_ date: Date, fmt: String = kDateFormat) -> String {
let formatter = DateFormatter.format(fmt);
return formatter.string(from: date);
}
/// String -> Date
static func dateFromString(_ dateStr: String, fmt: String = kDateFormat) -> Date? {
let formatter = DateFormatter.format(fmt);
let tmp = dateStr.count <= fmt.count ? dateStr : (dateStr as NSString).substring(to: fmt.count)
let result = formatter.date(from: tmp);
return result
}
/// 时间戳字符串 -> 日期字符串
static func stringFromInterval(_ interval: String, fmt: String = kDateFormat) -> String {
let date = Date(timeIntervalSince1970: interval.doubleValue)
return DateFormatter.stringFromDate(date, fmt: fmt);
}
/// 日期字符串 -> 时间戳字符串
static func intervalFromDateStr(_ dateStr: String, fmt: String = kDateFormat) -> String {
guard let date = DateFormatter.dateFromString(dateStr, fmt: fmt) else {
return "0" }
return "\(date.timeIntervalSince1970)";
}
}
Data
import UIKit
@objc public extension NSData{
/// NSData -> 转数组/字典
var objValue: Any? {
if JSONSerialization.isValidJSONObject(self) {
return nil;
}
do {
let obj: Any = try JSONSerialization.jsonObject(with: self as Data, options: [])
return obj;
} catch {
print(error)
}
return nil;
}
/// NSData -> 转字符串
var stringValue: String {
if let result = String(data: self as Data, encoding: .utf8) {
return result
}
return ""
}
///文件大小
var fileSize: String {
let length: CGFloat = CGFloat(self.length)
if length < 1024.0 {
return String(format: "%.2fB", length*1.0)
}
if length >= 1024.0 && length < (1024.0*1024.0) {
return String(format: "%.2fKB", length/1024.0)
}
if length >= (1024.0*1024.0) && length < (1024.0*1024.0*1024.0) {
return String(format: "%.2fMB", length/(1024.0*1024.0))
}
return String(format: "%.2fGB", length/(1024.0*1024.0*1024.0))
}
}
public extension Data{
/// 转数组/字典
var objValue: Any? {
return (self as NSData).objValue;
}
/// NSData -> 转字符串
var stringValue: String? {
return (self as NSData).stringValue;
}
/// NSData -> 转字符串
var fileSize: String {
return (self as NSData).fileSize;
}
}
Array
public extension Array{
/// ->Data
var jsonData: Data? {
return (self as NSArray).jsonData;
}
/// ->String
var jsonString: String {
return (self as NSArray).jsonString;
}
///同 subarrayWithRange:
func subarray(_ range: NSRange) -> Array {
return self.subarray(range.location, range.length)
}
///同 subarrayWithRange:
func subarray(_ loc: Int, _ len: Int) -> Array {
assert((loc + len) <= self.count);
return Array(self[loc...len]);
}
}
@objc public extension NSArray{
/// ->Data
var jsonData: Data? {
var data: Data?
do {
data = try JSONSerialization.data(withJSONObject: self, options: []);
} catch {
print(error)
}
return data;
}
/// ->NSString
var jsonString: String {
guard let jsonData = self.jsonData as Data?,
let jsonString = String(data: jsonData, encoding: .utf8) as String?
else { return "" }
return jsonString
}
}
Dictionary
import UIKit
public extension Dictionary{
/// ->Data
var jsonData: Data? {
return (self as NSDictionary).jsonData;
}
/// ->NSString
var jsonString: String {
return (self as NSDictionary).jsonString;
}
var plistData: Data?{
return (self as NSDictionary).plistData;
}
}
public extension Dictionary where Key == String, Value == String {
/// 键值翻转
var reversed: [String : String] {
var dic = [String : String]()
for (key, value) in self {
dic[value] = key
}
return dic;
}
///根据键数值排序
func valuesByKeySorted() -> [String] {
let values = keys.sorted {
// return $0.intValue < $1.intValue
return $0.compare($1) == .orderedAscending
}.map { self[$0] ?? ""}
return values
}
}
@objc public extension NSDictionary{
/// ->Data
var jsonData: Data? {
var data: Data?
do {
data = try JSONSerialization.data(withJSONObject: self, options: []);
} catch {
print(error)
}
return data;
}
/// ->NSString
var jsonString: String {
guard let jsonData = self.jsonData as Data?,
let jsonString = String(data: jsonData, encoding: .utf8) as String?
else { return "" }
return jsonString
}
var plistData: Data?{
let result = try? PropertyListSerialization.data(fromPropertyList: self, format: .binary, options: 0)
return result
}
}
URL
import UIKit
public extension URLComponents {
///查询参数
var queryParameters: [String: String]? {
guard let queryItems = queryItems else { return nil }
var dic = [String: String]()
for item in queryItems {
dic[item.name] = item.value
}
return dic
}
///追加查询参数
mutating func appendingQueryParameters(_ parameters: [String: String]) -> URL {
queryItems = (queryItems ?? []) + parameters
.map { URLQueryItem(name: $0, value: $1) }
return url!
}
///查询对应参数值
func queryValue(for key: String) -> String? {
return queryItems?
.first(where: { $0.name == key })?
.value
}
}
public extension URL {
///查询参数
var queryParameters: [String: String]? {
guard let components = URLComponents(url: self, resolvingAgainstBaseURL: false)
else { return nil }
return components.queryParameters
}
///追加查询参数
func appendingQueryParameters(_ parameters: [String: String]) -> URL {
var components = URLComponents(url: self, resolvingAgainstBaseURL: true)!
return components.appendingQueryParameters(parameters)
}
///查询对应参数值
func queryValue(for key: String) -> String? {
return URLComponents(string: absoluteString)?.queryValue(for: key)
}
}
@objc public extension NSURLComponents {
///查询参数
var queryParameters: [String: String]? {
return (self as URLComponents).queryParameters
}
///追加查询参数
func appendingQueryParameters(_ parameters: [String: String]) -> URL {
queryItems = (queryItems ?? []) + parameters
.map { URLQueryItem(name: $0, value: $1) }
return url!
}
///查询对应参数值
func queryValue(for key: String) -> String? {
return (self as URLComponents).queryValue(for: key)
}
}
@objc public extension NSURL {
///查询参数
var queryParameters: [String: String]? {
return (self as URL).queryParameters
}
///追加查询参数
func appendingQueryParameters(_ parameters: [String: String]) -> URL {
return (self as URL).appendingQueryParameters(parameters)
}
///查询对应参数值
func queryValue(for key: String) -> String? {
return (self as URL).queryValue(for: key)
}
}
UINavigationController
public extension UINavigationController{
///泛型方法: push到特定控制器页面
final func pushVC(_ type: T.Type, animated: Bool = true, block: ((T) -> Void)? = nil) {
let controller = type.init()
// controller.hidesBottomBarWhenPushed = true
block?(controller)
pushViewController(controller, animated: animated);
}
///泛型方法: pop到特定控制器页面
final func popToVC(_ type: T.Type, animated: Bool = true) {
for e in viewControllers {
if e.isKind(of: type) {
popToViewController(e, animated: animated)
return
}
}
popViewController(animated: animated)
}
///泛型方法: 延迟退出
func popVC(animated: Bool, delay: Double) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime(floatLiteral: delay)) {
self.popViewController(animated: animated)
}
}
}
UISegmentedControl
@objc public extension UISegmentedControl{
private struct AssociateKeys {
static var items = "UISegmentedControl" + "items"
}
/// 控件items
var items: [String] {
get {
if let obj = objc_getAssociatedObject(self, &AssociateKeys.items) as? [String] {
return obj
}
return []
}
set {
objc_setAssociatedObject(self, &AssociateKeys.items, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
updateItems(newValue)
}
}
/// 配置新item数组
private func updateItems(_ items: [String]) {
if items.count == 0 {
return
}
removeAllSegments()
for e in items.enumerated() {
insertSegment(withTitle: e.element, at: e.offset, animated: false)
}
selectedSegmentIndex = 0
}
}
present
@objc public extension UIViewController{
/// 呈现
func present(_ animated: Bool = true, completion: (() -> Void)? = nil) {
guard let keyWindow = UIApplication.shared.keyWindow,
let rootVC = keyWindow.rootViewController
else { return }
self.modalPresentationStyle = .fullScreen
DispatchQueue.main.async {
if let alertVC = self as? UIAlertController {
if alertVC.preferredStyle == .alert {
if alertVC.actions.count == 0 {
rootVC.present(alertVC, animated: animated, completion: {
DispatchQueue.main.after(TimeInterval(kDurationToast), execute: {
alertVC.dismiss(animated: animated, completion: completion)
})
})
} else {
rootVC.present(alertVC, animated: animated, completion: completion)
}
} else {
//防止 ipad 下 sheet 会崩溃的问题
if UIDevice.current.userInterfaceIdiom == .pad {
if let popoverPresentationController = alertVC.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
popoverPresentationController.sourceView = keyWindow;
let isEmpty = popoverPresentationController.sourceRect.equalTo(.null) || popoverPresentationController.sourceRect.equalTo(.zero)
if isEmpty {
popoverPresentationController.sourceRect = CGRect(x: keyWindow.bounds.midX, y: 64, width: 1, height: 1);
}
}
}
rootVC.present(alertVC, animated: animated, completion: completion)
}
} else {
rootVC.present(self, animated: animated, completion: completion)
}
}
}
}
备注:
let list = [1,2,4,3,9,8];
let b = list[2...5];// ArraySlice
ArraySlice不能长期保存,可能会有内存泄漏,附上官方api的截图
Important
Long-term storage of ArraySlice instances is discouraged. A slice holds a reference to the entire storage of a larger array, not just to the portion it presents, even after the original array’s lifetime ends. Long-term storage of a slice may therefore prolong the lifetime of elements that are no longer otherwise accessible, which can appear to be memory and object leakage.
警告:不鼓励/建议长时间的存储ArraySlice实例
由于一个ArraySlice实例呈现的是某个比较大的数组上的一个视图。如果这个原始数组已经结束了其生命周期,存储这个切片实例可能会延长那些不能再被访问的数组元素的存活时间,这就造成了明显的内存和对象泄露。为了防止这个影响的发生,只在临时性的计算时,使用ArraySlice。
//MARK:字典排序
func sortDictiony() -> Void {
//字典排序
/*
字典中$0 来表示闭包的第一个参数,$1 来表示第二个,以此类推,in 也可以省略
元组 **(key: String, value: String) 第0个是 key,第一个是 value **
dict.sorted { (<#(key: String, value: String)#>, <#(key: String, value: String)#>) -> Bool in
<#code#>
}
*/
let dict = ["27":"w","15":"t","36":"b"]
let dicSortedByKey = dict.sorted(by: {$0.0 < $1.0})
let dicSortedByValue = dict.sorted(by: {$0.1 < $1.1})
print(dicSortedByKey)
print(dicSortedByValue)
let dicSortedByKeyNew = dict.sorted(by:<)
let dicSortedByValueNew = dict.sorted(by:>)
print(dicSortedByKeyNew)
print(dicSortedByValueNew)
}