写在前面:
回想了一下这个项目,接手到现在也就是一个多月,真正难过的或许也只是理解Java代码并变成Swift,和后面联调的过程。多的不说,记录一下遇到的问题,争取能巩固,提高技术。
还需要一点点前奏:
现在Framework的制作方法真是,只要你想找,总有你要的。所以我挑了一个内容丰富一点的,供您参考。iOS 制作静态库 .a 文件 和 .framework 文件 以及解决第三方库冲突问题 (转载 mark 一下) - Luck_Developer的博客 - 博客频道 - CSDN.NET
进入正题:
那么现在,一个空的Framework应该已经被搭建完成并且编译通过了。其实本来我也只是想讲讲代码问题 :)。不得不说,关键在于,Swift严格的类型检查给我在调用C的Api的时候带来了不少小麻烦。
Q1.Java的[Byte]
如何在Swift中实现?
A: Java的Byte数据类型,真身就是Int8。那么,我们只要:
typealias Byte = Int8
然后给String加一个扩展方法就可以啦
extension String
{
func getBytes()->[Byte]
{
var byteArray = [Byte]()
for char in utf8
{
byteArray.append(Byte(char))
}
return byteArray
}
}```
*****
Q2.Java字符串的```trim```方法如何在Swift中实现?
A: 同样只要给String加一个扩展方法
extension String
{
func trim()->String
{
return contains(" ") ? trimmingCharacters(in: CharacterSet(charactersIn: " ")) : self
}
}
*****
Q3.那么,有时候Swift会把C的Api中,Java的```Byte```类型,识别成```UInt8```,导致参数要求是```[Byte]```,实际必须传```[UInt8]```(Swift:没错,我说它是```UInt```,你就得传```UInt```!),怎么破?
A: 多的不说见代码。**不过,千万不要轻易尝试类似如下的代码:**
let num1:Int8 = 0
let num2 = UInt8(num1)
__正确的⬇️⬇️__
func toInt8Array(arr:[UInt8])->[Int8]
{
var temp = Int8
for c in arr
{
temp.append(Int8(bitPattern: c))
}
return temp
}
func toUInt8Array(arr:[Int8])->[UInt8]
{
var temp = UInt8
for c in arr
{
temp.append(UInt8(bitPattern: c))
}
return temp
}
而且,我不会说我把好的东西都放在后面。
*****
Q4.Java中,arrayCopy这样的操作在Swift中如何实现?
A: 确实拿到手后纠结了一小会。多的不说你们自己看代码
func arrayCopy<T>(src:Array<T>,srcPos:Int,dest:Array<T>,destPos:Int,length:Int)->Array<T>
{
var temp = dest
for i in 0..<length
{
if i < src.count
{
temp[destPos + i] = src[srcPos + i]
}
}
return temp
}
这里写了一个__泛型__函数,不知道什么是泛型以及在这个函数中作用的,请问问度娘,她会教你的:)
*****
__Q5.各种算法__
一直很赞同算法是一个好程序的灵魂。
**Base64---Encode:**
internal func base64Encode(array:[UInt8])->String
{
return Data.init(bytes: array, count: array.count).base64EncodedString(options: Data.Base64EncodingOptions.endLineWithLineFeed)
}
internal func base64Encode(array:[Int8])->String
{
return Data.init(bytes: array, count: array.count).base64EncodedString(options: Data.Base64EncodingOptions.endLineWithLineFeed)
}
By the way,```internal```关键字是因为我写在了一个单独的文件中,不熟悉的可以去查一下访问控制。这里写两个方法呢,也只是为了应付@Swift,(sad face)
**Base64---Decode:**
internal func base64Decode(base64String:String)->[UInt8]
{
let data = Data.init(base64Encoded: base64String, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
var tempArr = [UInt8]()
for i in 0..<data.count
{
tempArr.append(data[i])
}
return tempArr
}
so,不要问我代码里为什么直接```!```,而不用```if let { }```或者```guard let else { throw }```,我相信你注意到了形参名是什么~
**SHA1**
internal func sha1(string: String) -> String
{
var Sha1Result = ""
if let data = string.data(using: String.Encoding.utf8)
{
var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
CC_SHA1((data as NSData).bytes, CC_LONG(data.count), &digest)
for index in 0..<CC_SHA1_DIGEST_LENGTH
{
Sha1Result += String(format: "%02x", digest[Int(index)])
}
}
return Sha1Result
}
**CRC32**
�偷偷懒,拿个OC的凑合用吧,记得导入<zlib.h>
- (uint32_t)CRC32Value
{
uLong crc = crc32(0L, Z_NULL, 0);
crc32(crc, self.bytes, self.length);
return crc;
}
*****
Q6.那么,序列化
A: 当我一开始知道,要将一个未知的模型转化成JSON的时候,其实我的心里是拒绝的。OC有MJExtension,Swift有Reflect了,拿来主义不就行了!但是在Framework里导入别人的框架不到万不得已,个人觉得还是不要这么干,原因有三,1.自己把握方法实现,出Bug了好查一点。2.还要做必要的配置工作,3.文件夹在明里会多3个文件。。好吧总结123就是,懒懒懒。
那么,希望你们碰到这样需求的时候不会苦逼的要抽方法,抽模型出来调试:
extension NSObject
{
func getProperty() throws ->[String:Any?]
{
struct getPropertyError: Error
{
var ErrorReason:String
init(reason:String)
{
ErrorReason = reason
}
}
var props = [String:Any?]()
var outCount:UInt32 = 0
if let properties = class_copyPropertyList(classForCoder, &outCount)
{
for i in 0..<outCount
{
if let name = String(cString: property_getName(properties[Int(i)]), encoding: String.Encoding.utf8),let value = value(forKey: name)
{
props[name] = value
}
else
{
//不能允许转换不完全
throw getPropertyError(reason:"转换失败")
}
}
}
return props
}
}
*****
Q7. 最后的最后,网络部分。
A: 模型变字典,然后愉快的(~~并不~~)变成了JSON之后,我们要和服务器通讯了。Java�如果用流式传输,就是创建```Stream```对象然后用```read```or```write```方法给服务器传输数据,oh,no!To be frank,不习惯。怎么办?
我们有```URLSession```.
举个POST方法的例子吧。
First:定义一个```URLRequest```,设置
req.httpMethod = "POST"
然后把要上传的数据准备好,这个例子就讲完了。(完结撒花,此处有没有👏不重要)
*****
“Wait,URLSession方法是异步的呀,放在有返回值的方法里,回调还没执行,方法就return啦!”
“......”
//创建信号量
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.uploadTask(with: req, from: data, completionHandler: {
(resData, response, error) in
/*do something */
//�终于等到你 还好我没放弃
semaphore.signal()
}).resume()
//如果要给等待加一个期限 我希望是永远
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
*****
到这里基本上所有的大坑都踩完了。剩下的整理整理想一想遗漏的再更新啦,谢谢看到这里的人,希望你们喜欢,也希望对你们有帮助。
如果觉得写的入得了各位看官老爷的法眼,请不要吝啬点个赞,Thank u very much!💗
*****
**最后感谢**[@xiaoheng](http://www.jianshu.com/users/bafc9a0f5df2/timeline),[@瑾瑾小泉](http://www.jianshu.com/users/d7ffbe4ce951)两位在闲暇时刻的讨论支持:)