ksnowlv

回顾过去,总结以往;立足现在,铭记当下;技术为主,笔记而已.

Swift中escaping与noescaping之区别

| Comments

Swift3之前

默认escaping,逃逸闭包,是不安全的。对于非逃逸闭包,你需要标记@noescaping

Swift3及之后

默认是noescaping,非逃逸的,默认是安全的:如果一个函数参数可能导致引用循环,那么它需要被escaping显示地标记出来.

一.区别

具体什么区别呢?先举例说明。

  • 1 声明testBlock
1
typealias testBlock = (_ type: Int, _ contextObject: Any) -> Void
  • 2 noescaping
1
2
3
func testBlock1(block:testBlock) {
    block(0,"hello");
}
  • 3 escaping
1
2
3
4
5
   func testBlock2(block:@escaping testBlock) {
        DispatchQueue.global().async {
            block(1,"world")
        }
    }
  • 4 调用
1
2
3
4
5
6
  testBlock1(block:{ (type: Int, contextObject: Any) in
        print("type=\(type),contextObject=\(contextObject)")
    } )
    testBlock2(block: {(type: Int, contextObject: Any) in
        print("type=\(type),contextObject=\(contextObject)")
    })
  • 5 输出日志
1
2
type=0,contextObject=hello
type=1,contextObject=world

二.区别总结

  • 1.@escaping标明这个闭包是会“逃逸”,通俗点来讲,这个闭包的作用域可能超过该函数的作用域,也就是说,该闭包在函数执行完成之后才被调用。

  • 2.@noescaping标明非逃逸的闭包的作用域是不会超过函数作用域的,我们不需要担心在闭包内持有self。

NS_SWIFT_NAME与@objc区别与用途

| Comments

NS_SWIFT_NAME与@objc有什么区别和用途呢?

  • NS_SWIFT_NAME:在objective-c中,重新命名在swift中的名称
  • @objc 在swift中,重新命名在objective-c中的名称。

示例1如下:

1
2
3
4
5
6
7
8
9
typedef NS_ENUM(NSUInteger, NetErrorType) {
    NetErrorTypeNone NS_SWIFT_NAME(None),
    NetErrorTypeNetError NS_SWIFT_NAME(NetError) ,
};

@interface YKBaseUIViewController : UIViewController
- (void)handleConnectItem:(YKConnectionItem *)connectionItem withParser:(YKJsonParser *)parser NS_SWIFT_NAME(handleNetResponse(connectionItem:parser:));

@end

在swift中调用如下:

1
2
3
NetErrorType.None
let baseUIViewController : YKBaseUIViewController = YKBaseUIViewController()
baseUIViewController.handleNetResponse(connectionItem: nil, parser: nil)

示例2如下:

1
2
3
4
@objc(showMyAge: address:)
public static func showMyInfo(age: Int, address: String) -> String{
        return "ksnowlv"
    }

在objective-c中调用如下:

1
NSString *string =  [YKDevice showMyAge:0 address:@"abc"];

Swift-framework的合并

| Comments

swift framework如何支持合并呢?以YKBaseFramework.framework为例。

1.lipo合并静态库。

1
 lipo -create Release-iphoneos/YKBaseFramework.framework/YKBaseFramework Debug-iphonesimulator/YKBaseFramework.framework/YKBaseFramework -output YKBaseFramework

生成YKBaseFramework,查看支持架构

1
2
bogon:YKBaseSwiftFrameworkLib ksnowlv$ lipo -info YKBaseFramework
Architectures in the fat file: YKBaseFramework are: armv7 i386 x86_64 arm64

2.把debug库中的swiftdoc与swiftmodule文件拷贝到release库对应目录下。

image

3.把合并后的YKBaseFramework文件拷贝到release库对应目录下.

image

4.大功告成,可以支持swift/objective-c调用

swift-cocoaframework中module.map配置]

| Comments

在swift framework中,如果要引用c库,可采用配置module.map.

那如何配置呢?我们以CommonCrypto为例。

一.工程目录下创建CommonCrypto文件夹,并分别创建module.mapYKBaseFramework-C.h
  • 1.module.map
1
2
3
4
5
6
7
8
module CommonCrypto [system] {
    //header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h"

    //header "/usr/include/CommonCrypto/CommonCrypto.h"
    header "YKBaseFramework-C.h"
    link "CommonCrypto"
    export *
}

目录如下图,注意目录的相对路径 image

  • 2.YKBaseFramework-C.h
1
2
3
4
5
6
7
8
9
10
11
12
13
//  YKBaseFramework-C.h
//  YKBaseFramework
//
//  Created by ksnowlv on 2018/7/4.
//  Copyright © 2018年 ksnowlv. All rights reserved.
//

#ifndef YKBaseFramework_C_h
#define YKBaseFramework_C_h

#include <CommonCrypto/CommonCrypto.h>

#endif /* YKBaseFramework_C_h */
二.设置module.map编译器目录引用路径。

在Build Settings, Swift Compiler – Search Paths 下 Import Paths中设置目录路径即可。

注意与上图目录实际位置一致!!!

image

三.引用CommonCrypto

注意clean,在swift code直接引入CommonCrypto即可。

1
2
3
import Foundation
import Security
import CommonCrypto

4.其它

  • 1.为什么不采用直接配置绝对路径引用CommonCrypto.h?

    配置为绝对路径,灵活性通用性实在太差,依赖于系统目录。

  • 2.配置CommonCrypto时,注意目录所在路径
  • 3.https://github.com/IBM-Swift/CommonCrypto

Swift-objective-c混编的framework

| Comments

swift-objective-c混编的framework如何制作呢?

  • 1.创建cocoaTouchframework,
  • 2.把需要导出的头文件添加到Headers中,如下图 image

  • 3.把头文件添加到导出头文件

1
2
3
4
5
6
7
8
9
10
11
//! Project version number for YKBaseFramework.
FOUNDATION_EXPORT double YKBaseFrameworkVersionNumber;

//! Project version string for YKBaseFramework.
FOUNDATION_EXPORT const unsigned char YKBaseFrameworkVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <YKBaseFramework/PublicHeader.h>

//#import <YKBaseFramework/YKFile.h>

#import <YKBaseFramework/YKString.h>

Swiftframework方法如何导出

| Comments

swift framework中的方法如何在objective-c中调用呢?

类或属性加@objc public

stackoverflow的解答

To access a swift class in objc, that is not inherited from NSObject you need to: @objc public class VeediUtils

A Swift class or protocol must be marked with the @objc attribute to be accessible and usable in Objective-C. This attribute tells the compiler that this piece of Swift code can be accessed from Objective-C. If your Swift class is a descendant of an Objective-C class, the compiler automatically adds the @objc attribute for you.

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@objc public class YKFile: NSObject {

    @objc public var fileName : String?

    @objc public var myData : Data?

    @objc public func myFilePath() -> String {
        return "ksnowlv"
    }

    @objc public static func name() -> String {
        return "ksnowlv"
    }
}

takeUnretainedValue与takeRetainedValue区别

| Comments

swift中,如果我们使用perform相关函数时,例如

1
2
3
4
 if let object = connectionItem.perform(connectionSEL, with: nil) {
                    (object as! YKURLConnection).cancel()

                }

此时会报警告

 Cast from 'Unmanaged<AnyObject>' to unrelated type 'YKURLConnection' always fails

虽然代码可以正常运行,报这种警告,也是让人心理很不爽。

Swift-散列算法md5

| Comments

swift中散列算法md5很常用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    func md5() -> NSString {

        guard self.length > 0 else {
            return self
        }

        let utf8Buf = self.cString(using: String.Encoding.utf8.rawValue)
        let length = self.lengthOfBytes(using: String.Encoding.utf8.rawValue)

        let buffer = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: Int(CC_MD5_DIGEST_LENGTH))
        buffer.initialize(to: 0)
        CC_MD5(utf8Buf,CC_LONG(length), buffer)

        let md5String = NSMutableString()

        for i in 0 ..< CC_MD5_DIGEST_LENGTH {
            md5String.appendFormat("%02x", buffer[Int(i)])
        }

        buffer.deallocate()

        return md5String.uppercased as NSString
    }

记得在bridging-header中导入头文件

  • CommonCrypto/CommonDigest.h

Swift之url编解码

| Comments

url的编码与解码,在工程中很常用,编解码针对特殊字符及中文,确保url可以正常访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let KUrlCodingReservedCharacters = "!*'();:|@&=+$,/?%#[]{}"

extension NSString {

    /// url编码
    ///
    /// - Returns: NSString
    func urlEncode() -> NSString? {
        return self.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: KYKUrlCodingReservedCharacters).inverted)! as NSString

    }

    /// url解码
    ///
    /// - Returns: NSString
    func urlDecode() -> NSString? {
        return self.removingPercentEncoding as NSString?
    }
}
Included file 'custom/after_footer.html' not found in _includes directory