iOS之面試題:騰訊三次面試以及參考思路

来源:http://www.cnblogs.com/rglmuselily/archive/2017/12/14/8038480.html
-Advertisement-
Play Games

使用了第三方庫, 有看他們是怎麼實現的嗎? 例:SD、YY、AFN、MJ等! <1>.SD為例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ...


  1. 使用了第三方庫, 有看他們是怎麼實現的嗎?

例:SD、YY、AFN、MJ等!

<1>.SD為例:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 1.入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage 顯示,然後 SDWebImageManager 根據 URL 開始處理圖片。 2.進入 SDWebImageManagerdownloadWithURL:delegate:options:userInfo:, 交給 SDImageCache 從緩存查找圖片是否已經下載 queryDiskCacheForKey:delegate:userInfo:. 3.先從記憶體圖片緩存查找是否有圖片, 如果記憶體中已經有圖片緩存,SDImageCacheDelegate 回調 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。 4.SDWebImageManagerDelegate 回調 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。 5.如果記憶體緩存中沒有,生成 NSInvocationOperation 添加到隊列開始從硬碟查找圖片是否已經緩存。 6.根據 URLKey 在硬碟緩存目錄下嘗試讀取圖片文件。 這一步是在 NSOperation 進行的操作,所以回主線程進行結果回調 notifyDelegate:。 7.如果上一操作從硬碟讀取到了圖片,將圖片添加到記憶體緩存中 (如果空閑記憶體過小,會先清空記憶體緩存)。 SDImageCacheDelegate 回調 imageCache:didFindImage:forKey:userInfo:。 進而回調展示圖片。 8.如果從硬碟緩存目錄讀取不到圖片, 說明所有緩存都不存在該圖片,需要下載圖片, 回調 imageCache:didNotFindImageForKey:userInfo:。 9.共用或重新生成一個下載器 SDWebImageDownloader 開始下載圖片。 10.圖片下載由 NSURLConnection 來做, 實現相關 delegate 來判斷圖片下載中、下載完成和下載失敗。 11.connection:didReceiveData: 中 利用 ImageIO 做了按圖片下載進度載入效果。 12.connectionDidFinishLoading: 數據下載完成後交給 SDWebImageDecoder 做圖片解碼處理。 13.圖片解碼處理在一個 NSOperationQueue 完成, 不會拖慢主線程 UI。如果有需要對下載的圖片進行二次處理, 最好也在這裡完成,效率會好很多。 14.在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成, imageDecoder:didFinishDecodingImage:userInfo 回調給 SDWebImageDownloader。 15.imageDownloader:didFinishWithImage: 回調給 SDWebImageManager 告知圖片下載完成。 16.通知所有的 downloadDelegates 下載完成, 回調給需要的地方展示圖片。 17.將圖片保存到 SDImageCache 中, 記憶體緩存和硬碟緩存同時保存。 寫文件到硬碟也在以單獨 NSInvocationOperation 完成, 避免拖慢主線程。 18.SDImageCache 在初始化的時候會註冊一些消息通知, 在記憶體警告或退到後臺的時候清理記憶體圖片緩存 應用結束的時候清理過期圖片。 19.SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。 20.SDWebImagePrefetcher 可以預先下載圖片, 方便後續使用。

2.強連通分量瞭解嘛?

概念:

有向圖強連通分量:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通(strongly

connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly

connected components)。

定義:

有向圖強連通分量:

在有向圖G中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(strongly connected)。

如果有向圖G的每兩個頂點都強連通,則稱G是一個強連通圖。

非強連通圖有向圖的極大強連通子圖,成為強連通分量(strongly connected components)。

下圖中,子圖{1,2,3,4}為一個強連通分量,因為頂點1,2,3,4兩兩可達,{5},{6}也分別是兩個強連通分量。

1.jpg

直接根據定義,用雙向遍歷取交際的方法求強連通分量,時間複雜度為O(N^2+M)。更好的方法是Kosaraju演算法或者Tarjan演算法

兩者的時間複雜度都是O(N+M)。本文介紹的是Tarjan演算法。

演算法原理:(Tarjan)

need-to-insert-img

Tarjan演算法是基於對圖深度優先搜索的演算法,每個強連通分量為搜索樹中的一顆子樹。

搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以盤對棧頂到棧中的節點是否為一個強連通分量。

定義DFN(u)為節點u搜索的次序編號(時間戳)。Low(u)為u或者u的子樹能夠追溯到的最早的棧中的節點的次序號。

由定義可以得出:

Low(u)= Min { DFN(u), Low(v)} ((u,v)為樹枝邊,u為v的父節點DFN(v),(u,v)為指向棧中節點的後向邊(非橫叉邊))

當DFN(u)=Low(u)時,以u為根的搜索子樹上所有節點是一個強連通分量。

3.遇到tableView卡頓嘛?會造成卡頓的原因大致有哪些?

可能造成tableView卡頓的原因有:

1.最常用的就是cell的重用, 註冊重用標識符

如果不重用cell時,每當一個cell顯示到屏幕上時,就會重新創建一個新的cell

如果有很多數據的時候,就會堆積很多cell。

如果重用cell,為cell創建一個ID,每當需要顯示cell 的時候,都會先去緩衝池中尋找可迴圈利用的cell,如果沒有再重新創建cell

2.避免cell的重新佈局

cell的佈局填充等操作 比較耗時,一般創建時就佈局好

如可以將cell單獨放到一個自定義類,初始化時就佈局好

3.提前計算並緩存cell的屬性及內容

當我們創建cell的數據源方法時,編譯器並不是先創建cell 再定cell的高度

而是先根據內容一次確定每一個cell的高度,高度確定後,再創建要顯示的cell,滾動時,每當cell進入憑虛都會計算高度,提前估算高度告訴編譯器,編譯器知道高度後,緊接著就會創建cell,這時再調用高度的具體計算方法,這樣可以方式浪費時間去計算顯示以外的cell

4.減少cell中控制項的數量

儘量使cell得佈局大致相同,不同風格的cell可以使用不用的重用標識符,初始化時添加控制項,

不適用的可以先隱藏

5.不要使用ClearColor,無背景色,透明度也不要設置為0

渲染耗時比較長

6.使用局部更新

如果只是更新某組的話,使用reloadSection進行局部更

7.載入網路數據,下載圖片,使用非同步載入,並緩存

8.少使用addView 給cell動態添加view

9.按需載入cell,cell滾動很快時,只載入範圍內的cell

10.不要實現無用的代理方法,tableView只遵守兩個協議

11.緩存行高:estimatedHeightForRow不能和HeightForRow裡面的layoutIfNeed同時存在,這兩者同時存在才會出現“竄動”的bug。所以我的建議是:只要是固定行高就寫預估行高來減少行高調用次數提升性能。如果是動態行高就不要寫預估方法了,用一個行高的緩存字典來減少代碼的調用次數即可

12.不要做多餘的繪製工作。在實現drawRect:的時候,它的rect參數就是需要繪製的區域,這個區域之外的不需要進行繪製。例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判斷是否需要繪製image和text,然後再調用繪製方法。

13.預渲染圖像。當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在bitmap context里先將其畫一遍,導出成UIImage對象,然後再繪製到屏幕;

14.使用正確的數據結構來存儲數據。

4.M、V、C相互通訊規則你知道的有哪些?

MVC 是一種設計思想,一種框架模式,是一種把應用中所有類組織起來的策略,它把你的程式分為三塊,分別是:

M(Model):實際上考慮的是“什麼”問題,你的程式本質上是什麼,獨立於 UI 工作。是程式中用於處理應用程式邏輯的部分,通常負責存取數據。

C(Controller):控制你 Model 如何呈現在屏幕上,當它需要數據的時候就告訴 Model,你幫我獲取某某數據;當它需要 UI 展示和更新的時候就告訴 View,你幫我生成一個 UI 顯示某某數據,是 Model 和 View 溝通的橋梁。

V(View):Controller 的手下,是 Controller 要使用的類,用於構建視圖,通常是根據 Model 來創建視圖的。

要瞭解 MVC 如何工作,首先需要瞭解這三個模塊間如何通信。

MVC通信規則

2.jpg

Controller to Model

可以直接單向通信。Controller 需要將 Model 呈現給用戶,因此需要知道模型的一切,還需要有同 Model 完全通信的能力,並且能任意使用 Model 的公共 API。

Controller to View

可以直接單向通信。Controller 通過 View 來佈局用戶界面。

Model to View

永遠不要直接通信。Model 是獨立於 UI 的,並不需要和 View 直接通信,View 通過 Controller 獲取 Model 數據

View to Controller

View 不能對 Controller 知道的太多,因此要通過間接的方式通信。

Target

action。首先 Controller 會給自己留一個 target,再把配套的 action 交給 View 作為聯繫方式。那麼 View

接收到某些變化時,View 就會發送 action 給 target 從而達到通知的目的。這裡 View 只需要發送

action,並不需要知道 Controller 如何去執行方法。

代理。有時候 View 沒有足夠的邏輯去判斷用戶操作是否符合規範,他會把判斷這些問題的權力委托給其他對象,他只需獲得答案就行了,並不會管是誰給的答案。

DataSoure。View 沒有擁有他們所顯示數據的權力,View 只能向 Controller 請求數據進行顯示,Controller 則獲取 Model 的數據整理排版後提供給 View。

Model 訪問 Controller

同樣的 Model 是獨立於 UI 存在的,因此無法直接與 Controller 通信,但是當 Model 本身信息發生了改變的時候,會通過下麵的方式進行間接通信。

Notification & KVO一種類似電臺的方法,Model 信息改變時會廣播消息給感興趣的人 ,只要 Controller 接收到了這個廣播的時候就會主動聯繫 Model,獲取新的數據並提供給 View。

從上面的簡單介紹中我們來簡單概括一下 MVC 模式的優點。

1.低耦合性

2.有利於開發分工

3.有利於組件重用

4.可維護性

5.NStimer準嗎?談談你的看法?如果不准該怎樣實現一個精確的NSTimer?

1.不准

2.不准的原因如下:

1、NSTimer加在main runloop中,模式是NSDefaultRunLoopMode,main負責所有主線程事件,例如UI界面的操作,複雜的運算,這樣在同一個runloop中timer就會產生阻塞。

2、模式的改變。主線程的 RunLoop 里有兩個預置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。

當你創建一個 Timer 並加到 DefaultMode 時,Timer 會得到重覆回調,但此時滑動一個ScrollView時,RunLoop 會將 mode 切換為 TrackingRunLoopMode,這時 Timer 就不會被回調,並且也不會影響到滑動操作。所以就會影響到NSTimer不准的情況。

PS:DefaultMode 是 App 平時所處的狀態,rackingRunLoopMode 是追蹤 ScrollView 滑動時的狀態。

方法一:

1、在主線程中進行NSTimer操作,但是將NSTimer實例加到main runloop的特定mode(模式)中。避免被覆雜運算操作或者UI界面刷新所干擾。

self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

2、在子線程中進行NSTimer的操作,再在主線程中修改UI界面顯示操作結果;

1 2 3 4 5 6 7 8 9 10 11 12 - (void)timerMethod2 { NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil]; [thread start]; } - (void)newThread { @autoreleasepool { [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showTime) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] run]; } }

總結:

一開始的時候系統就為我們將主線程的main runloop隱式的啟動了。

在創建線程的時候,可以主動獲取當前線程的runloop。每個子線程對應一個runloop

方法二:

使用示例

使用mach內核級的函數可以使用mach_absolute_time()獲取到CPU的tickcount的計數值,可以通過”mach_timebase_info”函數獲取到納秒級的精確度 。然後使用mach_wait_until(uint64_t deadline)函數,直到指定的時間之後,就可以執行指定任務了。

關於數據結構mach_timebase_info的定義如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct mach_timebase_info {uint32_t numer;uint32_t denom;}; #include #include static const uint64_t NANOS_PER_USEC = 1000ULL; static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC; static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC; static mach_timebase_info_data_t timebase_info; static uint64_t nanos_to_abs(uint64_t nanos) { return nanos * timebase_info.denom / timebase_info.numer; } void example_mach_wait_until(int seconds) { mach_timebase_info(&timebase_info); uint64_t time_to_wait = nanos_to_abs(seconds * NANOS_PER_SEC); uint64_t now = mach_absolute_time(); mach_wait_until(now + time_to_wait); }

方法三:直接使用GCD替代!

1829339-fc2188dff714cb30.gif

 

 

iOS面試題:騰訊二面以及參考思路:

  1. 編譯過程做了哪些事情?

1.C++,Objective C都是編譯語言。編譯語言在執行的時候,必須先通過編譯器生成機器碼,機器碼可以直接在CPU上執行,所以執行效率較高。

iOS開發目前的常用語言是:Objective和Swift。二者都是編譯語言,換句話說都是需要編譯才能執行的。二者的編譯都是依賴於Clang + LLVM. OC和Swift因為原理上大同小異,知道一個即可!

iOS編譯

不管是OC還是Swift,都是採用Clang作為編譯器前端,LLVM(Low level vritual machine)作為編譯器後端。所以簡單的編譯過程如圖

3.jpg

編譯器前端

編譯器前端的任務是進行:語法分析,語義分析,生成中間代碼(intermediate representation )。在這個過程中,會進行類型檢查,如果發現錯誤或者警告會標註出來在哪一行。

5.jpg

編譯器後端

編譯器後端會進行機器無關的代碼優化,生成機器語言,並且進行機器相關的代碼優化。iOS的編譯過程,後端的處理如下

LVVM優化器會進行BitCode的生成,鏈接期優化等等

4.jpg

LLVM機器碼生成器會針對不同的架構,比如arm64等生成不同的機器碼。

6.jpg

執行一次XCode build的流程

當你在XCode中,選擇build的時候(快捷鍵command+B),會執行如下過程

編譯信息寫入輔助文件,創建編譯後的文件架構(name.app)

處理文件打包信息,例如在debug環境下

7.jpg

執行CocoaPod編譯前腳本

例如對於使用CocoaPod的工程會執行CheckPods Manifest.lock

編譯各個.m文件,使用CompileC和clang命令。

編譯各個.m文件,使用CompileC和clang命令。

1 2 3 4 5 6 1.CompileC ClassName.o ClassName.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler 2.export.US-ASCII 3.export PATH="..." 4.clang-x objective-c -arch x86_64 -fmessage-length=0 -fobjc-arc... -Wno-missing-field-initializers ... -DDEBUG=1 ... -isysroot iPhoneSimulator10.1.sdk -fasm-blocks ... -I 上文提到的文件 -F 所需要的Framework-iquote 所需要的Framework ... -c ClassName.c -o ClassName.o

通過這個編譯的命令,我們可以看到

8.jpg

2.字典大致實現原理;

一:字典原理

NSDictionary(字典)是使用hash表來實現key和value之間的映射和存儲的

方法:- (void)setObject:(id)anObject forKey:(id)aKey;

Objective-C中的字典NSDictionary底層其實是一個哈希表

二:哈希原理

散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。

給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數後若能得到包含該關鍵字的記錄在表中的地址,則稱表M為哈希(Hash)表,函數f(key)為哈希(Hash) 函數。

哈希概念:哈希表的本質是一個數組,數組中每一個元素稱為一個箱子(bin),箱子中存放的是鍵值對。

三:哈希存儲過程

1.根據 key 計算出它的哈希值 h。

2.假設箱子的個數為 n,那麼這個鍵值對應該放在第 (h % n) 個箱子中。

3.如果該箱子中已經有了鍵值對,就使用開放定址法或者拉鏈法解決衝突。

在使用拉鏈法解決哈希衝突時,每個箱子其實是一個鏈表,屬於同一個箱子的所有鍵值對都會排列在鏈表中。

哈希表還有一個重要的屬性: 負載因數(load factor),它用來衡量哈希表的空/滿程度,一定程度上也可以體現查詢的效率,計算公式為:

負載因數 = 總鍵值對數 / 箱子個數

負載因數越大,意味著哈希表越滿,越容易導致衝突,性能也就越低。因此,一般來說,當負載因數大於某個常數(可能是 1,或者 0.75 等)時,哈希表將自動擴容。

哈希表在自動擴容時,一般會創建兩倍於原來個數的箱子,因此即使 key 的哈希值不變,對箱子個數取餘的結果也會發生改變,因此所有鍵值對的存放位置都有可能發生改變,這個過程也稱為重哈希(rehash)。

哈希表的擴容並不總是能夠有效解決負載因數過大的問題。假設所有 key 的哈希值都一樣,那麼即使擴容以後他們的位置也不會變化。雖然負載因數會降低,但實際存儲在每個箱子中的鏈表長度並不發生改變,因此也就不能提高哈希表的查詢性能。

基於以上總結,細心的朋友可能會發現哈希表的兩個問題:

1.如果哈希表中本來箱子就比較多,擴容時需要重新哈希並移動數據,性能影響較大。

2.如果哈希函數設計不合理,哈希表在極端情況下會變成線性表,性能極低。

3.block和函數指針的理解;

相似點:

函數指針和Block都可以實現回調的操作,聲明上也很相似,實現上都可以看成是一個代碼片段。

函數指針類型和Block類型都可以作為變數和函數參數的類型。(typedef定義別名之後,這個別名就是一個類型)

不同點:

函數指針只能指向預先定義好的函數代碼塊(可以是其他文件裡面定義,通過函數參數動態傳入的),函數地址是在編譯鏈接時就已經確定好的。

Block本質是Objective-C對象,是NSObject的子類,可以接收消息。

函數裡面只能訪問全局變數,而Block代碼塊不光能訪問全局變數,還擁有當前棧記憶體和堆記憶體變數的可讀性(當然通過__block訪問指示符修飾的局部變數還可以在block代碼塊裡面進行修改)。

從記憶體的角度看,函數指針只不過是指向代碼區的一段可執行代碼,而block實際上是程式運行過程中在棧記憶體動態創建的對象,可以向其發送copy消息將block對象拷貝到堆記憶體,以延長其生命周期。

4.一般開始做一個項目,你的架構是如何思考的?

參考文章一

參考文章二

5.你瞭解的UIKit結構?

9.jpg

這題應該是在你回答的基礎之上,進行二次提問,主要還是看你的基礎!

1829339-7a9e8f203d135b7f.gif

 

 

iOS面試題:騰訊三面

1.OC你瞭解的鎖有哪些?在你回答基礎上進行二次提問;

追問一:自旋和互斥對比?

追問二:使用以上鎖需要註意哪些?

追問三:用C/OC/C++,任選其一,實現自旋或互斥?口述即可!

2.記憶體泄漏可能會出現的幾種原因,聊聊你的看法?

追問一:非OC對象如何處理?

追問二:地圖類記憶體若泄漏,如何處理?

追問三:若常用框架出現記憶體泄漏如何處理?

3.容錯處理你們一般是怎麼做的?

4.項目開始容錯處理沒做?如何防止攔截潛在的崩潰?

作者:不懂技術的愛迪生

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、什麼是MongoDB? MongoDB 是一個基於分散式文件存儲的資料庫。 MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。 MongoDB 將數據存儲為一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔類似 ...
  • 工作中需要創建SQL Job對資料庫進行定期備份,現把腳本記錄如下。 1. 完整備份: 2. 差異備份: 以上兩段可以分別創建兩個SQL Job,比如完整備份的作業可以定在每周天凌晨運行,執行成功後刪掉之前的備份文件(代碼中有刪除的語句),差異備份的作業定在周一到周六每天凌晨運行。 ...
  • 1什麼會增加主從延遲? 1 網路不好 2 從庫硬體差 3 索引沒做好,從庫執行慢 4 從庫鎖等待,多見於myisam 5 主庫寫頻繁,從庫單線程執行慢 6 使用row複製,或mix使用行複製 2如何優化,減少延遲時間? 1 如何寫頻繁,水平拆分,減少單片寫數量 2 避免複雜DML操作 3幾個因為主從 ...
  • 1. 配置Yum源及關閉SeLinux 2. 安裝桌面環境(如果未安裝) 3. 安裝軟體包 4. 建立用戶 5. 建立文件夾 6. 配置系統核心參數,Oracle用戶資源限制,Oracle用戶環境變數 7. 編輯主機名 8. 解壓安裝文件 9. 開始安裝 [oracle@localhost ~]$ ...
  • 目錄: 前言 SQL Server基礎準備 1.新建資料庫 2.在數據中添加表 3.向表中添加數據 SQL Server與C#基礎準備 實例解析 1.C#連接資料庫 2.查詢特定列數據 3.使用列別名 4.在列上加入計算 5.使用比較設置條件 總結 1.新建資料庫 2.在數據中添加表 3.向表中添加 ...
  • 最近公司的泛微OA無法訪問,Oracle資料庫也無法正常啟動,嘗試了好多方法,終於解決了,先說說基本情況,希望能給碰到同樣問題的朋友帶來一點幫助。 ...
  • 當出現這種問題是網上的解答方案都是一模一樣的! 我這邊先給個地址講的是解決方案http://blog.csdn.net/qq_25827845/article/details/52974991 但是我踩的坑是 我電腦連的是WiFi跟測試真機是一樣的地址!但是我在真機上設置伺服器地址的時候我的ip地址 ...
  • 可以看到QQ上的ToolBar其實就是一個自定義的view,可以看到不同的界面就是簡單地修改了文字而已,在第二張與第三張尤其的明顯,我們就仿QQ的這個Toolbar設置一個自定義控制項 在開始之前,首先瞭解一下官方是如何實現一個控制項的,比如說一個Linearlayout 它不是有layout_widt ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...