Swift 创建一个自己的命名空间

介绍

Swift的三方库,比如 RxSwift 中的 rx, Kingfisher 中的 kf,给类别添加了一个前缀,就想写一个自己的前缀在项目中使用,可用区别工程中自己添加的独有扩展方法。实现起来非常简单。

新建一个swift 文件,实现命名空间的代码如下:

import Foundation
import UIKit

/// 1.声明一个结构体, 结构体内部会持有一个任意类型的对象
public struct ULWrapper<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

/// 2.声明协议, 让想要的类遵守此协议
public protocol ULCompatible { }

/// 3.提供协议的默认实现, object.ul, 会在ul中持有object
extension ULCompatible {

    /// 实例变量及方法命名空间
    public var ul: ULWrapper<Self> {
        get { return ULWrapper(self) }
    }

    /// 类变量及方法命名空间
    public static var ul: ULWrapper<Self>.Type {
        get { return ULWrapper<Self>.self }
    }

}

/// 4.让任意对象(类,结构体,协议都可以)遵守协议
/// 类遵守协议, 就可以使用  UIImageView.ul获取到第一步的结构体对象
extension UIImageView : ULCompatible { }
extension UIColor : ULCompatible { }
/// 结构体遵守协议, 就可以使用Int.ul
extension Int : ULCompatible { }
/// 枚举遵守协议,就可以使用 UIView.ContentMode.ul
extension UIView.ContentMode : ULCompatible { }


/// 5.给指定类的对象扩展结构体的方法, 一定要加限定
//给对象添加扩展, 加限定  where Base: 对应的子类,
extension ULWrapper where Base: UIImageView {

    func setImageWithUrl(_ url : URL?,
                         placeHolder : UIImage? = nil) {
        print("当前函数:",#function)
        print("self: ",self,"self.base: ",self.base)
        // self.base 就是对应的UIImageView对象
        self.base.image = placeHolder
        print("请求接口...")
        DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: DispatchWorkItem(block: {
            print("请求接口成功")
            self.base.image = UIImage.init(named: "1")
        }))
    }


    static func showInfo() {
        // 调用原有的类方法,
        // 目前只能通过这种方式, 因为当前的self是ULWrapper类型,不是实例,无法使用self.base
        UIImageView.setAnimationsEnabled(false)
        print("类方法",self, #function)
    }

}


// 演示给结构体添加扩展, 加限定 where Base == 结构体类型
extension ULWrapper where Base == Int {
    @discardableResult
    func square() -> Int {
        // self.base 就是对应的int结构体对象
        return self.base * self.base
    }

    @discardableResult
    static func halfMax() -> Int {
        return Int.max / 2
    }

}

// 演示给枚举添加扩展,
extension ULWrapper where Base == UIView.ContentMode {
    func printInfo() {
        // self.base 就是对应的UIView.ContentMode结构体对象
        print(self.base, "对应的Int值为", self.base.rawValue)
    }
}

思路:

  1. 创建一个 Wrapper 的对象,它是一个容器,里面会包含一个泛型对象 base,实际上真正做事的是这个 base 对象。

  2. 写一个  Compatible 空协议,

  3. 给协议添加默认实现, 默认为它添加一个 ul 属性,这样一来,只要我想为某对象A 添加 ul 命名空间,就只需要让A 遵守 Compatible 协议: extension A: Compatible {} ,就可以让 a 拥有 a.ul 属性。

  4. ul 属性返回的是一个 包裹了 a对象 的 Wrapper<A> 对象, 在扩展结构中可以使用, self.base 获取到 a对象

  5. 假设A类拥有一个方法 doSomething() ,那么,为 Wrapper 写一个扩展方法 doSomething(),就可以在其中调用 base.doSomething() 方法了。

// 类使用
let imageView = UIImageView()
imageView.backgroundColor = .gray
imageView.frame = CGRect.init(x: 100, y: 100, width: 170, height: 270)
imageView.ul.setImageWithUrl(URL(string: "图片地址") ?? nil)
self.view.addSubview(imageView)
UIImageView.ul.showInfo()

// 结构体使用
var a = 10
a = a.ul.square()
print("a=",a)
print("Int.ul.halfMax() = ",Int.ul.halfMax())

// 枚举使用
UIView.ContentMode.scaleAspectFill.ul.printInfo()


print(type(of: self),#function,self)
当前函数: setImageWithUrl(_:placeHolder:)
请求接口...
类方法 ULWrapper<UIImageView> showInfo()
a= 100
Int.ul.halfMax() =  4611686018427387903
UIViewContentMode 对应的Int值为 2
ViewController viewDidLoad() <SwiftScrollViewDemo.ViewController: 0x13a507540>
请求接口成功

替换系统用法

例如,在 iOS 13 之后,系统默认的 present方法使用 modalPresentationStyle = .pageSheet 样式弹出,即弹出的 ViewController顶部会留部分距离是有暗色半透明背景。

但是项目中暂不需要这样的风格,所以在 Lg+UIViewController.swift 文件中,以 lg 为命名空间 对 UIViewController 进行扩展,代码如下:

extension LgWrapper where Base: UIViewController {
    func present(_ viewController: UIViewController, presentationStyle: UIModalPresentationStyle = .fullScreen, animated: Bool, completion: (() -> Void)? = nil) {
        if viewController.modalPresentationStyle == .pageSheet {
            viewController.modalPresentationStyle = presentationStyle
        }

        base.present(viewController, animated: animated, completion: completion)
    }
}

使用的时候加上 .lg.present

viewController.lg.present(vc2, animated: true, completion: nil)

 iOS Swift 写一个自己的命名空间 - 简书

swift开发之扩展实现命名空间(实例方法,类方法) - 简书

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值