原文地址:PJ 的 iOS 開發平常html
Vary 是一款我十分喜歡的工具,官方 slogan 爲「分享不拘一格」,是「輕量級的社交網絡,重量級的創造工具」。從去年 8 月 9 日加入 Vary 開發組到如今已經整整過去半年了......在 17 年初時,從知乎上得知到了 Dandy Weng 對 Vary 的宣傳。沒記錯的話,當時應該是在上軟件工程課,刷知乎看到了這篇文章。刷完後我又把做者的全部相關信息都看了一遍,趕忙申請了 TestFlight 的測試資格,很是幸運的申請到了。git
一打開 Vary app,當時直接抓了坐在旁邊的妹子來一同把玩,瞬間被 Vary 捕獲了芳心!我從未想到 app 還能夠這麼作!交互體驗還能夠這麼好!UI 實在太精美了!能夠說直到如今,我都沒遇到第二個可以讓我發出如此讚歎的 app。我持續使用到了如今,而且也加了做者的微信,在使用過程當中一直在持續不斷的給做者報 bug,就是由於太喜歡了,因此報 bug 報到去年 8 月 9 日,我發現了一個復現週期比較長的 bug,Dandy 直接邀請我加入了開發團隊!你們感興趣能夠閱讀這篇文章。github
當時我正在搬磚,直接從椅子上喊了一聲站了起來!我竟然能夠加入 Vary 的開發了!我就要加入本身十分喜好的 app 開發工做了!後來,咱們對接了目前的開發工做,當時肯定要進行的內容有:web
Emoji
保存時閃退;(這個 bug 讓我好幾回編輯的長文都沒了)剛開始我負責的是修復插入新版 Emoji
時保存的閃退問題,最後由於工做事情太多了,這部分工做又交回給 Dandy 了哈哈哈~過了一段時間後,開始優化首頁信息流卡片高度緩存的問題,Vary 在架構上仍是有必定的細節問題存在的,致使前期看代碼時有些恍惚,後來 Dandy 幾乎是每週都來問我進度,但當時正值秋招火熱時,忙着三方和課設等各類瑣碎的事情,天天只有額外多餘的兩個小時的空餘時間來作本身的事情,因此最後實在被 Dandy 問煩了直接逼着本身弄完了首頁信息流卡片緩存的一期優化,但偶爾仍是會出現高度不許確的問題,只能放到二期優化中去作了。數組
後來時間實在是推不開,跟 Dandy 說了等到放了寒假再繼續跟進。我覺得 Dandy 會「放過」我了哈哈哈,從寒假到如今磕磕碰碰的作出了「卡片草稿」和「定時保存」兩個主需求。在下文中,我將在脫離 Vary 核心代碼的前提下講解開發這兩個有趣的需求時遇到的問題和思考。緩存
卡片草稿的需求比較容易梳理,但由於對相關邏輯代碼的不熟悉致使開發流程修改了好幾回,最後肯定的開發流程是這樣的:服務器
定時保存跟 Dandy 討論了好幾回,在討論的過程當中發現以前寫好的「卡片草稿」功能的實現思路不是正確的,致使又繼續返工到如今。最後咱們討論的結果是:微信
對 Vary 的開發並無一直在持續,只是有時間就修修補補。針對上文中所梳理出的兩個需求,着重看了 Vary 中相關邏輯,讓我感到意外的是,Vary 中對卡片的渲染並非利用 Native 能力進行渲染的,我說怎麼有時候感受不跟手,覺得這個有點「卡頓」的狀況只是個小問題,沒想到當我看到了這篇文章後,深深的感覺到是我錯了,原來 webKit
裏連這都有點小問題。網絡
接下來繼續熟悉代碼。發現了原來每一張卡片都是 WKWebView
,直接渲染了下載的 HTML
字符串,並且在 Native 中作了很多 JS 代碼注入的東西,看到這裏後我心裏開始有些許的失落,由於並無看到我想看的東西,Vary 中的自動排版引擎實際上並非我想的那麼「高大上」,簡單來講是下了不少「苦功夫」,沒有不少吸引我眼球的地方。不過看到了一個讓我驚喜到笑出了聲的實現。數據結構
在 Dandy 的文章中對 Vary 的宣傳點其中有一部分是這樣的:
同時我也在不斷研究如何經過技術手段來引導交互層面的創新,例如 Vary 的 iOS App 能夠檢測手指接觸屏幕的面積,並以此來調整卡片的滾動速度:用指尖滑動時,一次只會滾動一張卡片;整個手指貼在屏幕上滑動時,則會根據你滑動速度的慣性來連續滾動多張卡片。這聽起來也許有些玄乎,卻很是容易上手,也很實用。
當我翻到了相關實現後,真的就驚喜的笑了出來,至於爲何會這般驚喜的笑了出來,該功能核心是利用了 touch
對象的 majorRadius
屬性,若是你真的很想推測出 Vary 具體的實現究竟是怎麼樣的,推薦你仔細把玩十幾分鍾後也可以猜的出來。
隨後,我開始研究「模塊編輯」頁面的代碼,該模塊中的代碼邏輯十分清晰,嗯,就是你如今腦海中直覺冒出來的那個實現思路。Vary 中最有趣的地方莫過於看各個模塊的實現了,其中最讓我感到興奮的是「圖片」和「語音」模塊,又仔細研究一番後,我都已經摩拳擦掌的給本身心理準備,一上午就好好研究這兩個模塊的實現好了,但等我都看完具體實現後,一看時間,原來只過去了半小時。若是有常常關注我 github 的同窗,「語音」模塊是用了開源庫。「圖片」模塊之因此可以在我心裏中佔據這麼大的份額,就是由於它精美的 UI,本覺得實現也很完美,但實際上讓我驚歎的是以前開發同窗的新奇思路而已,這點最感到失望!
零零碎碎的熟悉了至關長的時間後,開始在返工和繼續開發以及作了一些微小的重構工做中來來回回,本來想着直接給 Vary 來一波大的重構,但想到如今這個時間點仍是先不要給本身找太多沒必要要的事情了。
卡片草稿的核心圍繞着 NSFileManager
進行展開。由於只保存單一數據,沒有必要上 Core Data
,但在首頁卡片信息流的後續開發中有涉及到緩存一系列相同數據的地方,並且還會涉及到部分卡片的更新,若是這個時候再使用 NSFileManager
進行緩存數據的管理就會顯得有些拘謹,此時使用 Core Data
是一件再適合不過的事情。
首先,針對 Vary 中的緩存策略須要涉及的邏輯寫了封裝了一個簡單的基於 NSFileManager
的管理類 PJCache
,這與核心業務無關,具體實現以下:
//
// PJCache.h
// Vary
//
// Created by PJHubs on 2019/2/10.
// Copyright © 2019 Vary iOS Team. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface PJCache : NSObject
// 建立文件
+(BOOL)cacheFileSet:(NSString*)fileName contents:(NSString*)contents;
// 經過 NSData 建立緩存文件
+(BOOL)cacheFileSetNSdata:(NSString*)fileName contents:(NSData*)contents;
// 讀取緩存文件,返回 NSData
+(NSData*)cacheFileGetNSdata:(NSString*)fileName;
// 緩存文件 是否存在
+(BOOL)cacheFileExists:(NSString*)fileName;
// 緩存文件 刪除
+(BOOL)cacheFileDelete:(NSString*)fileName;
@end
複製代碼
//
// PJCache.m
// Vary
//
// Created by PJHubs on 2019/2/10.
// Copyright © 2019 Vary iOS Team. All rights reserved.
//
#import "PJCache.h"
@implementation PJCache
// 建立文件
+(BOOL)cacheFileSet:(NSString*)fileName
contents:(NSString*)contents {
NSError *err;
NSString *path = [self cacheFilePath:fileName];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:path]) {
[fm removeItemAtPath:path error:&err];
}
return [fm createFileAtPath:path
contents:[contents dataUsingEncoding:NSUTF8StringEncoding]
attributes:nil];
}
// 經過 NSData 建立緩存文件
+(BOOL)cacheFileSetNSdata:(NSString*)fileName
contents:(NSData*)contents {
NSError *err;
NSString *path = [self cacheFilePath:fileName];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:path]) {
[fm removeItemAtPath:path error:&err];
}
return [fm createFileAtPath:path
contents:contents
attributes:nil];
}
// 讀取緩存文件,返回 NSData
+(NSData*)cacheFileGetNSdata:(NSString*)fileName {
NSString *path = [self cacheFilePath:fileName];
NSFileManager *fm=[NSFileManager defaultManager];
if ([fm fileExistsAtPath:path]) {
return [fm contentsAtPath:path];
}
return nil;
}
// 判斷緩存文件是否存在
+(BOOL)cacheFileExists:(NSString*)fileName {
NSString *path = [self cacheFilePath:fileName];
NSFileManager *fm=[NSFileManager defaultManager];
return [fm fileExistsAtPath:path];
}
// 刪除緩存文件
+(BOOL)cacheFileDelete:(NSString*)fileName {
NSString *path = [self cacheFilePath:fileName];
NSFileManager *fm=[NSFileManager defaultManager];
if ([fm fileExistsAtPath:path]) {
NSError *err;
return [fm removeItemAtPath:path error:&err];
}
return YES;
}
@end
複製代碼
寫入緩存時須要注意的時如緩存數據過大,注意必須進行異步現場的寫入和讀寫。卡片草稿一開始根本沒有考慮太多,根據實際業務邏輯調整好相關新增代碼後,緩存的時預覽卡片時接收到渲染完成的 html
字符串。當時 Dandy 還提了一個細節問題,「當存在緩存時,用戶下次再建立卡片時應該直接載入上一次未發佈卡片內容」,這句話我當時並無理解得很好,覺得要作到用戶一點擊「+」時,要以最快速度加載渲染完成的卡片。實際上的應該要作的對卡片哥哥模塊進行 encoder
,完成後直接把歸檔完成的「模塊」對象數組進行緩存。
這塊功能當時由於在完成「卡片草稿」需求時走錯了路子,致使在此基礎上進行的「自動保存」功能開發作設計時搞了比較複雜的一套流程,由於當時最終的目的要的是卡片渲染完成的 html
字符串,這就致使了「自動保存」時要每次都以拿到 html
字符串爲「保存」成功的標誌,這更加耗費服務器資源,幸好在跟 Dandy 屢次討論的過程當中被及時制止了。
「自動保存」功能的觸發在「模塊編輯」頁面,主要分爲兩種狀況:
在「文件編輯」頁面,利用 GCD
每隔 3s 針對用戶輸入的內容作「清洗判斷」,保證每次緩存時的內容與上一次緩存的內容徹底不一致且必定不爲空。在觸發「肯定」事件時,帶上最終用戶輸入的文本內容以及中止緩存且當即更新緩存至最新,以避免出現用戶在恰好完成上一次緩存 3s 間隔時,立馬輸入了個標點符合後直接退出,而致使文本內容的缺失。
其它模塊的「自動保存」上文也以及說了大概,由於用戶不會長時間滯留在非「文本」模塊中的其它模塊(不排除遺忘可能),因此這塊比較簡單粗暴,在各個模塊的「肯定」事件中,各自觸發一次緩存。
「自動保存」功能若是須要保存的數據結構較簡單,一樣能夠直接上 NSFileManager
。
完成以上兩個內容後,此次的版本迭代的主要任務也就完成了。由於天天只有區區不到三個小時的完整時間去作迭代維護,不少細節仍是沒能考慮好,Vary 依然有不少須要優化的地方,但因時間關係致使實在是難以投入大量的時間,真但願能有一個月的完整時間來對 Vary 好好的作一個大的維護呢~
但願你們可以喜歡體驗更好的 Vary,找到一個可以認真分享本身心裏世界的地方。