如果要初始化很多的子控件,这些控件的类别相同,正常的做法是创建一个命名一个,需要搞各种名字,复制来复制去,为避免这种麻烦,我们可以用下边的方式,就可以避免啦
//方式一:不需要拿到对象
({
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
总结
- 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 其他自定义类型throw
终止代码往下执行
1Code after 'throw' will never be executed
即: throw后边的代码无法被执行
2do{ try ... } catch { }
do 中代码一旦throw
异常,则终止do
中代码往下运行,进入到catch
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={健康码=不是绿色}
网友评论