swift 有趣的swift




如果要初始化很多的子控件,这些控件的类别相同,正常的做法是创建一个命名一个,需要搞各种名字,复制来复制去,为避免这种麻烦,我们可以用下边的方式,就可以避免啦

//方式一:不需要拿到对象
({
            let image = UIImage(named: "lg_circle_erweima")
            let imageView = UIImageView.init(image: image)
            addSubview(imageView)
            imageView.snp.makeConstraints { (make) in
                make.centerX.equalToSuperview().offset(-50)
                make.top.equalTo(actionImageView.snp.bottom).offset(15)
                make.width.equalTo(18)
                make.height.equalTo(18)
            }
})()
//方式二:需要拿到对象
let actionImageView = ({ () -> UIImageView in
            let image = UIImage(named: "lg_circle_yaoqing")
            let imageView = UIImageView.init(image: image)
            addSubview(imageView)
            imageView.snp.makeConstraints { (make) in
                make.centerX.equalToSuperview()
                make.top.equalTo(bgView).offset(130)
                make.width.equalTo(gl_kScreenWidth - 80)
                make.height.equalTo(image!.gl_imageCalculationHeight(gl_kScreenWidth - 80))
            }
            return imageView
})()

//在OC中的写法
UIImageView *myImageView = ({
        UIImageView *imageView = [[UIImageView alloc]init];
        imageView.image = [UIImage imageNamed:@"imagename"];
        [self addSubview:imageView];
        [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self);
        }];
        imageView;
});
({
        UIImageView *imageView = [[UIImageView alloc]init];
        imageView.image = [UIImage imageNamed:@"imagename"];
        [self addSubview:imageView];
        [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self);
        }];
});



pragma mark - 区块注释

image.png
// swift 中的写法
// MARK: delegate & datasource
// FIXME: 添加标记2

//OC 中的写法
#pragma mark - delegate & datasource



guard

func fooGuard(x: Int?) {
    guard let _x = x where x > 0 else {
        // 变量不符合条件判断时,执行下面代码
        return
    }
    // 使用x
    _x.description
}



奇怪的写法一func functionPerson<T>(person: Person, getter: (Person) -> T){}

class Person: NSObject{
    var personAge = 18
    
}
func functionPerson<T>(person: Person, getter: (Person) -> T) {
    print(getter(person))
    // 打印结果 --- 18
}

// 调用
func go(){
    //swift自动为闭包提供参数名缩写功能
    //可以直接通过$0和$1等来表示闭包中的第一个第二个参数
    //并且对应的参数类型会根据函数类型来进行判断
    functionPerson(person: Person.init(), getter: { $0.personAge })
}



参数类型的传递

想实现的效果是对于分页TableView网络请求的封装 ,使用的数组转模型HandyJSON
研究这里的原因: 调用static func deserialize(from array: [Any]?) -> [Element?]? {}是用[遵循HandyJSON代理的类]类型调用的

public extension Array where Element: HandyJSON {
    static func deserialize(from array: [Any]?) -> [Element?]? {
        return JSONDeserializer<Element>.deserializeModelArrayFrom(array: array)
    }
}
import UIKit
import HandyJSON
class GLBaseModel: NSObject , HandyJSON {
    required override init(){}
    var id:String?
    func mapping(mapper: HelpingMapper) {
        /*字段映射
        mapper.specify(property: &id, name: "customId")
        mapper <<<
            self.id <-- "customId"*/
    }
}
class lgss_circle_inviteListModel: GLBaseModel {
    var commission = ""// (number, optional): 收益佣金 ,
    var headIcon = ""   // (string, optional): 用户头像 ,
    var userName = ""   // (string, optional): 用户姓名
}
/// GET /circle/inviteList 邀请好友列表
func lgss_circle_inviteList(target: GLBaseTableViewController) {
    lgss_pagingRequest(target: target, path: "circle/inviteList", type: lgss_circle_inviteListModel.self)
    
}
/// ***********************************************************************************************
/// ***********************************************************************************************
///  ***********************************************************************************************
/// GLBaseTableViewController分页请求数据
func lgss_pagingRequest<T:GLBaseModel>(target : GLBaseTableViewController, path : String, type : T.Type){
    let parameter = ["pageSize":target.gl_pageSize, "pageNum":target.gl_pageNumber]
    GLNetWorkRequest(GLApiGeneral.getForm(path: path, para: parameter), hudView: nil) { (resp) in
        let array = [T].deserialize(from: resp as? Array<Any>) as? [T]
        guard let _arr = array else {
            target.tableView.mj_header?.endRefreshing()
            target.tableView.mj_footer?.endRefreshing()
            return
        }
        if target.gl_pageNumber == 1{
            target.gl_listArray.removeAll()
        }
        if _arr.count < target.gl_pageSize {
            target.tableView.mj_header?.endRefreshing()
            target.tableView.mj_footer?.endRefreshingWithNoMoreData()
        }else{
            if target.gl_pageNumber == 1{
                target.showRefreshFooter()
            }
            target.tableView.mj_header?.endRefreshing()
            target.tableView.mj_footer?.endRefreshing()
            target.gl_pageNumber += 1
        }
        target.gl_listArray.append(contentsOf: _arr)
        target.tableView.reloadData()
    }failed: { (any, code) in
        target.tableView.mj_header?.endRefreshing()
        target.tableView.mj_footer?.endRefreshing()
    } errorResult: {
        target.tableView.mj_header?.endRefreshing()
        target.tableView.mj_footer?.endRefreshing()
    }
}



关键字

image.png

image.png
    func userInfo() {
        self.rj_get_userInfo(with: "", age: 0)
    }
    @available(*, deprecated, message: "使用rj_get_userInfo_new替代")
    open func rj_get_userInfo( with name: String, age: Int, score: ((Double) -> Void)? = nil) -> Double? {
        score?(99)
        return 0.0
    }
    @discardableResult
    open func rj_get_userInfo_new(with name: String, age: Int, score: ((Double) -> Void)? = nil) -> Double? {
        score?(99)
        return 0.0
    }
/*知识点一: 表示警告已过期的方法
*/
@available(*, deprecated, message: "使用rj_get_userInfo_new替代")

/*知识点二: 表示如果我们调用一个带有返回值的函数,但是不使用返回值,就会得到Xcode编译警告。
该关键字就是为了消除警告,即可以不使用返回值
*/
@discardableResult

/*知识点三: 下边的方法自动生成两个方法,一个带有score参数,一个不带  ? = nil
*/
    open func rj_get_userInfo( with name: String, age: Int, score: ((Double) -> Void)? = nil) -> Double? {
        score?(99)
        return 0.0
    }

open 、public 、internal 、fileprivate 、private

    open class ClosureEventMonitor: EventMonitor {
        open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?
    }
    public enum ParameterEncoderFailureReason {
        public enum RequiredComponent {or during encoding.
            case url
            case httpMethod(rawValue: String)
        }
        case missingRequiredComponent(RequiredComponent)
        case encoderFailed(error: Error)
    }
    internal func widthConstraint() -> NSLayoutConstraint? {
        return constraint(with: self, attribute: .width)
    }
    fileprivate func unlock() {
        let error = pthread_mutex_unlock(mutex)
        precondition(error == 0, "Failed to unlock pthread_mutex")
    }

    private var mutableState = MutableState()

required(必须实现的协议) 、optional(可选实现的协议)

@protocol UITableViewDataSource<NSObject>
@required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; 
... ...
@end

//1.当子类没实现任何构造方法,编译器就会认为子类可以使用父类中的所有指定构造器,required修饰的构造方法在子类中可以不写
//2.当子类中定义了异于父类中的构造方法(参数名称不同、参数个数不同、参数类型不同),
//那么父类中使用required修饰的构造方法在子类中必须实现,而且这个方法必须使用required关键字而不能使用override修饰
class RJBaseView: UIView {
    override  init(frame: CGRect) {
        super.init(frame: frame)
        // code... ...
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

convenience(便利构造器)

------
    convenience init(frame: CGRect , placeholder : NSString,isShowMore : Bool) {
        self.init(frame: frame)
        isShowMoreP = isShowMore
        placeholderP = placeholder
    }
    /*
     required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
     }
     */
------
    init(frame: CGRect , placeholder : NSString,isShowMore : Bool) {
        isShowMoreP = isShowMore
        placeholderP = placeholder
        super.init(frame: frame)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
------

throw、throws、rethrows

总结

  1. throw <#Error#>
    1 <#Error#> 可以是NSError 例子:throw NSError.init(domain: NSString.init(format: "You must override %@ in a subclass.", #function) as String, code: 99, userInfo: nil)
    2 <#Error#> 可以是extension String : Error{} 例子:throw "throwErrorContent"
    3 <#Error#> 可以是enum RJEnumError : Error { case ErrorState(errorCode:Int, errorMessage:String) } 例子:throw RJEnumError.ErrorState(errorCode: 88, errorMessage: "我是自定义错误啊")
    4 其他自定义类型
  2. throw终止代码往下执行
    1Code after 'throw' will never be executed即: throw后边的代码无法被执行
    2 do{ try ... } catch { }do 中代码一旦throw异常,则终止do中代码往下运行,进入到catch
  3. rethrows 只能传递 参数中的 异常,不能自己产生异常'A function declared 'rethrows' may only throw if its parameter does'
    func throwsError(index aIndex:Int, closure:() throws -> Void) throws { 
        try closure()
        throw "在这里我可以throw哟"
    }
    func rethrowsError(index aIndex:Int, closure:() throws -> Void) rethrows {
        do {
            try closure()
        }
        catch {
            print("错误原因:\(error)")
            throw "我只可以在这里throw哟,如果不写do catch ,默认异常往上抛出"
        }
    }

    func throwErrorClosure() throws {
        throw "throwErrorClosure"
    }
    func throwErrorClosure2()  {
        print("没有异常")
    }
    func testThrowError(index aIndex:Int) {
        //报错(throws):Call can throw, but it is not marked with 'try' and the error is not handled
        throwsError(index: aIndex, closure: throwErrorClosure2)
        //正常(rethrows):没有异常的参数则不用try
        rethrowsError(index: aIndex, closure: throwErrorClosure2)
        do {
            //正常(throws):没有异常的参数需要try
            try throwsError(index: aIndex, closure: throwErrorClosure2)
            //正常(rethrows):有异常的参数需要try
            try rethrowsError(index: aIndex, closure: throwErrorClosure)
            // 一旦上边的代码抛出异常,则下边的代码不会执行,直接进入到catch

            //警告(rethrows): No calls to throwing functions occur within 'try' expression
            try rethrowsError(index: aIndex, closure: throwErrorClosure2)
            //Code ...
        }
        catch {
            print(error)
        }
    }

抛异常NSException

Swift #function 和 _cmd (Objective-C) : 获取当前方法

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let error = NSException(name: NSExceptionName.internalInconsistencyException,
                                reason: NSString.init(format: "You must override %@ in a subclass.", #function) as String,
                                userInfo: nil)
        print(error)
    }

print: You must override tableView(_:didSelectRowAt:) in a subclass.

swift 中throw 的对象不能是 NSException,只能是Error类型

#define MASMethodNotImplemented() \
    @throw [NSException exceptionWithName:NSInternalInconsistencyException \
                                   reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)] \
                                 userInfo:nil]

do{ try ... } catch { }

    func testThrowError() {
        do {
            try self.throwError()
        }
        catch {
            print("catch----Error")
            print(error.localizedDescription)
        }
    }
    func throwError() throws {
        throw NSError.init(domain: NSString.init(format: "You must override %@ in a subclass.", #function) as String, code: 99, userInfo: nil)
    }

print:
catch----Error
未能完成操作。(You must override throwError() in a subclass.错误99。)

switch

    switch switchV {
        case 1:// 不写大括号
            print("1111")
            fallthrough// 实现贯穿效果  功能同oc中的不写break
        // 可省略不写break
        default:
            print("2222")
        }

自定义和系统错误

    func testThrowError(index aIndex:Int) {
        do {
            try self.throwError(index: aIndex)
        }
        catch RJEnumError.ErrorState(let errorCode ,let errorMessage){
            print("错误码:\(errorCode) 错误原因:\(errorMessage)")
        }
        catch {
            print("catch----Error")
            print(error.localizedDescription)
        }
    }
    func throwError(index aIndex:Int) throws {
        switch aIndex {
        case 0:
            print("SUCCESS")
        case 1:
            throw RJEnumError.ErrorState(errorCode: 88, errorMessage: "我是自定义错误啊")
        case 2:
            throw NSError.init(domain: NSString.init(format: "You must override %@ in a subclass.", #function) as String, code: 99, userInfo: nil)
        default: break
        }
        
    }
    enum RJEnumError : Error {
        case ErrorState(errorCode:Int, errorMessage:String)
    }

print:
SUCCESS
错误码:88 错误原因:我是自定义错误啊
catch----Error
未能完成操作。(You must override throwError(index:) in a subclass.错误99。)

() -> Void类型可以传给 () throws -> Void类型,反过来则不能传递
即:() -> Void类型可转换为 () throws -> Void ,但() throws -> Void无法转换为() -> Void ,
() -> Void表示抛出异常的可能性为 0 罢了

字符串分割

    let string = "我是世界上最好的好人,你们说对吗"
    //string.components(separatedBy: T##StringProtocol)
    //string.components(separatedBy: T##CharacterSet)
    let resultArray1 = string.components(separatedBy: ",")
    let resultArray2 = string.components(separatedBy: CharacterSet.init(charactersIn: "世界好"))
    let resultArray3 = Array(string)
    
    print(resultArray1)//"," 单字符分割
    print(resultArray2)//"世""界""好" 三个字分割
    print(resultArray3)//字符串单字符","分开
    
    let s = "Hi! How are you? I'm fine. It is 6 p.m. Thank you! That's it."
    var sentences = [String]()
    s.enumerateSubstrings(in: s.startIndex..<s.endIndex, options: .bySentences) { (substring, substringRange, enclosingRange, stop) in
        sentences.append(substring!)
    }
    print(sentences)//英文文字分割

print:
["我是世界上最好的好人", "你们说对吗"]
["我是", "", "上最", "的", "人,你们说对吗"]
["我", "是", "世", "界", "上", "最", "好", "的", "好", "人", ",", "你", "们", "说", "对", "吗"]
["Hi! ", "How are you? ", "I\'m fine. ", "It is 6 p.m. ", "Thank you! ", "That\'s it."]

奇怪的写法二Result<Success, Failure>

抛出错误
Swift 5 已经伴随 Xcode 10.2 正式发布,该类型被加入到标准库

@frozen : 将此属性应用于结构或枚举声明,以限制可以对类型进行更改的种类。

@frozen public enum Result<Success, Failure> where Failure : Error {

    case success(Success)

    case failure(Failure)

    public func map<NewSuccess>(_ transform: (Success) -> NewSuccess) -> Result<NewSuccess, Failure>

    public func mapError<NewFailure>(_ transform: (Failure) -> NewFailure) -> Result<Success, NewFailure> where NewFailure : Error

    public func flatMap<NewSuccess>(_ transform: (Success) -> Result<NewSuccess, Failure>) -> Result<NewSuccess, Failure>

    public func flatMapError<NewFailure>(_ transform: (Failure) -> Result<Success, NewFailure>) -> Result<Success, NewFailure> where NewFailure : Error
    
    public func get() throws -> Success
    
    public init(catching body: () throws -> Success)
}
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        grj_goHome { (result) in
            switch result {
            case .success(let result):
                print("-----------------")
                print(result)
            case .failure(let error):
                print("+++++++++++++++++")
                print(error)
            }
        }
    }
    static var staticNumber = 0
    func grj_goHome(completionHandler:((Result<Any,Error>)) -> Void) {
        if <#Class#>.staticNumber%2==0 {
            completionHandler(.success("你的健康码是绿色,可以回家"))
        }else{
            let error = NSError.init(domain: "错误:你的健康码不是绿色,不能回家", code: 66, userInfo: ["健康码":"不是绿色"])
            completionHandler(.failure(error))
        }
        <#Class#>.staticNumber += 1
    }

print:
-----------------
你的健康码是绿色,可以回家
+++++++++++++++++
Error Domain=错误:你的健康码不是绿色,不能回家 Code=66 "(null)" UserInfo={健康码=不是绿色}

推荐阅读更多精彩内容