【編者按】本篇文章作者是 Reinder de Vries,既是一名企業(yè)家,也是優(yōu)秀的程序員,發(fā)表多篇應(yīng)用程序的博客。本篇文章中,作者主要介紹了如何基于 Parse 特點(diǎn),打造一款類似 Instagram 的應(yīng)用,完整而清晰的步驟,為開發(fā)者提供一次絕佳的學(xué)習(xí)體驗(yàn)。本文系 OneAPM 工程師編譯整理,這是本系列的第 3 篇文章。
如何用 Parse 和 Swift 搭建一個像 Instagram 那樣的應(yīng)用?(1)
如何用 Parse 和 Swift 搭建一個像 Instagram 那樣的應(yīng)用?(2)
使用 Swift 和自定義表視圖單元格
現(xiàn)在讓我們再次回歸代碼——已經(jīng)有足夠的接口。打開 CatsTableViewController.swift 并找到指定初始化 init(風(fēng)格:類名:)。
在這個方法中,我們可以在 self.parseClassName = className;下添加以下兩行代碼:
self.tableView.rowHeight = 350
self.tableView.allowsSelection = false
第一行設(shè)置合適的行高,第二行禁止單元格選擇。
然后添加下列代碼到 viewDidLoad just above super.viewDidLoad(): 方法
tableView.registerNib(UINib(nibName: "CatsTableViewCell", bundle: nil), forCellReuseIdentifier: cellIdentifier)
該行很可能引發(fā)錯誤。為了盡量不出錯,將下面代碼從 tableView 的 cellForRowAtIndexPat 方法移動到類的頂部,并重新將其值命名為「CatCell」。
let cellIdentifier:String = "Cell"
類的定義應(yīng)該類似這樣:
class CatsTableViewController: PFQueryTableViewController
{
let cellIdentifier:String = "CatCell"
override init!(style: UITableViewStyle, className: String!)
}
我們剛剛將 cellIdentifier 常量從局部方法范圍擴(kuò)展成類范圍,使得它在整個類中均可用,包括 tableView 的 cellForRowAtIndexPath 和 viewDidLoad。
接下來,我們用下面代碼替換 tableView 的 cellForRowAtIndexPath 的內(nèi)容:
var cell:CatsTableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? CatsTableViewCell
if(cell == nil) {
cell = NSBundle.mainBundle().loadNibNamed("CatsTableViewCell", owner: self, options: nil)[0] as? CatsTableViewCell
}
if let pfObject = object {
cell?.catNameLabel?.text = pfObject["name"] as? String
var votes:Int? = pfObject["votes"] as? Int
if votes == nil {
votes = 0
}
cell?.catVotesLabel?.text = "\(votes!) votes"
var credit:String? = pfObject["cc_by"] as? String
if credit != nil {
cell?.catCreditLabel?.text = "\(credit!) / CC 2.0"
}
}
return cell
你不禁疑惑,這與我們以前使用的舊代碼相比有什么區(qū)別?主要體現(xiàn)在:
- 單元格類型從 PFTableViewCell 改為 CatsTableViewCell
- 當(dāng)單元格為空,新單元格從我們剛才創(chuàng)建的 XIB 文件中得到。我們將從集合中檢索,賦予所有當(dāng)前類所有權(quán),然后將它轉(zhuǎn)換為 catstableviewcell。
- 然后,我們檢查對象是否存在,并嘗試將 Parse 對象的列名賦給它的文本屬性,就像之前那樣。
- 然后,catVotesLabel 和文本屬性也一樣。Parse 每列的票數(shù)是 String 類型,但不是 int,所以要轉(zhuǎn)換成 int 類型嗎?如果票數(shù)恰好是空值,那么我們就將其設(shè)置為零。然后,使用一種稱為字符串插值的騷亮技術(shù),設(shè)置標(biāo)簽文本。
最后,我們返回單元格。
讓我們再次運(yùn)行應(yīng)用程序。一切看上去太完美了!沒有 Bug 和死機(jī)!但是...圖像在哪兒?
從 Parse 異步下載圖像
圖像不見了,這怎么可以!讓我們加上它。在 TableView 的 cellForRowAtIndexPath 添加如下代碼「在最后一個 if 語句(用于信用標(biāo)簽)之后,在返回語句之前」。
var cell:CatsTableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? CatsTableViewCell
if(cell == nil) {
cell = NSBundle.mainBundle().loadNibNamed("CatsTableViewCell", owner: self, options: nil)[0] as? CatsTableViewCell
}
if let pfObject = object {
cell?.catNameLabel?.text = pfObject["name"] as? String
var votes:Int? = pfObject["votes"] as? Int
if votes == nil {
votes = 0
}
cell?.catVotesLabel?.text = "\(votes!) votes"
var credit:String? = pfObject["cc_by"] as? String
if credit != nil {
cell?.catCreditLabel?.text = "\(credit!) / CC 2.0"
}
}
return cell
哇!這里發(fā)生了什么?我們將 Parse 的 URL 列轉(zhuǎn)成了 NSURL 類型的實(shí)例。
我們用它在主操作隊列中啟動異步 NSURLConnection,其中下載圖像作為 NSData 對象。當(dāng)下載完成時關(guān)閉執(zhí)行。它分配下載得到 UIImage 的數(shù)據(jù),分配到 catImageView 的圖像屬性中。
在這里無需鉆研太深,因?yàn)樯厦娲a的復(fù)雜性與我們的應(yīng)用程序無關(guān)。但是,請注意以下幾點(diǎn):
- 使用 NSURLConnection 很方便,但有點(diǎn)枯燥。當(dāng)你使用互聯(lián)網(wǎng)上的數(shù)據(jù)源做更復(fù)雜的事情,請選擇優(yōu)秀的 AFNetworking (Objective-C)或 alamofire (Swift)庫。
- Parse 允許你將圖像存儲在云端,并能直接使用。它是 ParseUI 的組成部分,但它不允許外部 URL(貓圖片源自 Flickr)的調(diào)用。
- 在開始另一個異步連接之前,我們首先要明確主隊列中的所有操作。這是有點(diǎn)枯燥:它從隊列中移除 pending-and-unfinished 下載。嘗試刪除該行并運(yùn)行程序,你會看到所有圖像混合成一堆。當(dāng)它重新使用單元格時,出列機(jī)制不會重置任何掛起連接,因此圖像可以加載成功。
讓我們再運(yùn)行應(yīng)用,看看是否有效。
加碼 : Instagram 的類似功能
進(jìn)行到這一步了,真不容易!還有一些終極功能有待完善。接下來就讓我們來添加這些功能:類似「Instagram」的功能——你在圖片上雙擊,一個「贊+1」被添加到該貓的圖片上,并顯示一個干凈的小貓爪動畫。
首先,為爪子圖像到表視圖單元格添加出口。添加下面一行代碼到 CatsTableViewCell 類(在其他四個出口的下面):
@IBOutlet weak var catPawIcon:UIImageView?
在 Interface Builder 中添加一個 UIImageView 到 CatsTableViewCell.xib。還記得怎么做的嗎?
- 在對象庫中查找 UIImageView 類。
- 將它從對象庫中拖放到表視圖單元格。
確保將其向右拖動到其他圖像視圖的中心。調(diào)整新圖像,寬高均為 100 點(diǎn),它的 X 和 Y 均為大約110點(diǎn)。然后,當(dāng)圖像視圖已選中時,添加以下限制。
- Editor → Pin → Width
- Editor → Pin → Height
- Editor → Pin → Top Space To Superview
- Editor → Align → Horizontal Center In Container
正如下圖所示,使圖像視圖水平居中,固定寬度和高度為100點(diǎn),并保持它與頂部有固定的空間,有效地將其居中的貓圖像的放在正中心。

現(xiàn)在,通過從文檔的頂部選擇貓的表格視圖單元格,創(chuàng)建出口連接。再選擇 Connections Inspector 選項卡,從 catpawicon 單元格圖像視圖中繪出一條藍(lán)色的線。
接下來,下載 paw.zip。該文件包含三個圖形文件,是一個圖像的三種分辨率。在使用之前需要將它們導(dǎo)入。
首先,解壓縮文件;然后,打開 Xcode 中 Images.xcassets 文件;接著右鍵單擊左側(cè)列表(一個寫著 APPICON 的列表),然后單擊新建圖像集,或使用左下方的「加號」按鈕。重命名剛才創(chuàng)建的圖像集,打開其屬性。
現(xiàn)在,將剛才解壓的文件從 Finder 拖至打開的文件集。確保文件匹配:
- paw.png 是 1x.
- paw@2x.png 是 2x.
- paw@3x.png 是 3x.
看不到文件也不用擔(dān)心,因?yàn)樗鼈兌际前咨?/p>

然后,返回 CatsTableViewCell.xib 并選擇小圖像視圖。找到屬性檢查器,然后從在圖像下拉列表中選擇合適的爪子圖像。白色的爪子應(yīng)該像下圖這樣顯示在單元格視圖。

最后,請記住連接與 catPawIcon 出口和小圖像視圖。
現(xiàn)在,讓我們回到編碼。打開 Xcode 中的 CatsTableViewCell。將下面的代碼添加到 awakeFromNib 方法中(在super.awakeFromNib() 之前)。
let gesture = UITapGestureRecognizer(target: self, action:Selector("onDoubleTap:"))
gesture.numberOfTapsRequired = 2
contentView.addGestureRecognizer(gesture)
catPawIcon?.hidden = true
這里會發(fā)生兩種情況。
第一,我們建立一個 UITapGestureRecognizer,這樣我們便可以跟任何視圖互動。在這種情況下,我們將其添加到 contentView 查看,這個視圖包括單元格的兩個標(biāo)簽和兩個圖像視圖。它為 onDoubleTap: 初始化一個 target、self、一個動作和一個選擇器。所以,當(dāng)檢測到連續(xù)雙擊時,方法 onDoubleTap:of self(當(dāng)前類)被執(zhí)行。此外,我們設(shè)置連續(xù)數(shù)目為 2,使得它為雙擊響應(yīng)。
第二,我們隱藏 catPawIcon 出口。
其次,添加 onDoubleTap 方法到當(dāng)前類(在 awakeFromNib():函數(shù)之后)。
func onDoubleTap(sender:AnyObject) {
catPawIcon?.hidden = false
catPawIcon?.alpha = 1.0
UIView.animateWithDuration(1.0, delay: 1.0, options:nil, animations: {
self.catPawIcon?.alpha = 0
}, completion: {
(value:Bool) in
self.catPawIcon?.hidden = true
})
}
這種方法被稱為一個動作,始終需要一個參數(shù):AnyObject。在該方法中,可以實(shí)現(xiàn)以下動畫代碼:
- 首先,通過設(shè)置隱藏為 false,使 catPawIcon 可見。
- 然后,將 alpha 即透明度設(shè)置為1.0,完全可見。需要重置圖像狀態(tài),也就是當(dāng)動畫完成時 alpha 通道為0。
- 動畫的設(shè)置需要編程。UIView 的類方法被使用,這需要五個參數(shù):動畫時間、動畫前延遲、基本選項、動畫屬性的關(guān)閉,以及動畫完成時關(guān)閉的指令。
這時你會看到:
- 為了使圖像可見,我們可以設(shè)置它的 alpha 通道為可見。
- 稍等一下動畫延遲。
- 動畫 alpha 通道從1到0的時間不到一秒,這就是動畫周期。
- 動畫完成,隱藏圖像。
這個解決方案的最大好處在于它易于使用:代碼將完全管理動畫。我們只需要設(shè)置它的初始狀態(tài)、結(jié)束狀態(tài)、持續(xù)時間,以及動畫框架插補(bǔ)狀態(tài)和動畫步驟。從技術(shù)上來講,我們使用兩個屬性:一個連續(xù)的值 α,一個用來隱藏管理爪子圖像可見性的布爾值。
最后,運(yùn)行應(yīng)用,看看新功能能否正常適用。你可以雙擊一個單元格,簡要展示爪子圖標(biāo),雙擊然后淡出消失。

能運(yùn)行了嗎?太棒了!
用 Parse 整合投票
剩下要做的事就是給 Parse 貓對象增加投票數(shù)列,通過雙擊響應(yīng)投票動作。
那么我們怎么去實(shí)現(xiàn)呢?
首先,我們要改變的對象叫做 PFObject 類型的對象,在 CatsTableViewController 的 tableView 的 cellForRowAtIndexPath 方法中。我們不能從表視圖單元訪問它,因?yàn)樗陔p擊動作的方法內(nèi)。
我們不能移動 onDoubleTap 方法,所以我們需要在表視圖對象和表視圖單元之間創(chuàng)造引用。
我們采取以下步驟來實(shí)現(xiàn):
1.在 CatsTableViewCell 中,在類的頂部和網(wǎng)點(diǎn)下,編寫下列代碼創(chuàng)建一個新的屬性:
var parseObject:PFObject?
2.然后,在 tableView 里的 cellForRowAtIndexPath,編寫下面代碼(就在單元格 == nill 語句結(jié)束的大括號后面),如下:
cell?.parseObject = object
現(xiàn)在,我們已建立一個機(jī)制,將 cellForRowAtIndexPath 的對象復(fù)制到我們的表視圖單元,使得在 CatsTableViewCell 類的對象實(shí)例可用。
然后,調(diào)整 CatsTableViewCell的onDoubleTap 方法。在該方法的開始處添加下面代碼:
if(parseObject != nil) {
if var votes:Int? = parseObject!.objectForKey("votes") as? Int {
votes!++
parseObject!.setObject(votes!, forKey: "votes");
parseObject!.saveInBackground();
catVotesLabel?.text = "\(votes!) votes";
}
}
這段代碼可以實(shí)現(xiàn)以下工作:
- 檢查 parseObject 是否為空;
- 從 parseObject 得到票數(shù),并將它放在可選的 Int 中;
- 如果票數(shù)不為空,用 ++ 操作增加票數(shù)變量,與 votes = votes! + 1 有相同功能;
- 用 setObject 函數(shù)將票數(shù)變量返回給 parseObject 集;
- 調(diào)用 parseObject 的 saveInBackground() 方法!它在后臺將保存當(dāng)前對象,可能的時候?qū)⑵鋵懭?Parse 云端;
- 更新文本以反饋新的票數(shù),一切就是這么簡單,用 Command-R 或
Play
按鈕運(yùn)行程序,驗(yàn)證新功能是否實(shí)現(xiàn)。
運(yùn)行成功了嗎?太贊了!
小結(jié):
通過本篇文章,我們學(xué)習(xí)了以下內(nèi)容:
- 用 Parse 實(shí)現(xiàn)檢索,存儲數(shù)據(jù)到云端;
- Cocoapods整合一個調(diào)用 Objective-C 框架的 Swfit 程序;
- 建立視圖和有接口的自定義表視圖單元;
- 從零開始,用 Swift 編寫一個完整的 App;
- 使用自動布局和約束;
- 使用手勢識別、可選類型、條件、閉包、屬性、出口和動作。
你可以在這里下載整個爪子項目文件。使用 Xcode6.3(或以上)版本運(yùn)行項目。請注意,你必須改變 AppDelegate.swift 中的應(yīng)用程序鍵和客戶端密鑰。另外也要記住,如果你自己動手編寫這個完整的 App,對自己是個很好的提升機(jī)會。(完結(jié))
如何用 Parse 和 Swift 搭建一個像 Instagram 那樣的應(yīng)用?(1)
如何用 Parse 和 Swift 搭建一個像 Instagram 那樣的應(yīng)用?(2)
原文地址:http://www.appcoda.com/instagram-app-parse-swift/
本文系 OneAPM 工程師編譯整理。OneAPM 是應(yīng)用性能管理領(lǐng)域的新興領(lǐng)軍企業(yè),能幫助企業(yè)用戶和開發(fā)者輕松實(shí)現(xiàn):緩慢的程序代碼和 SQL 語句的實(shí)時抓取。想閱讀更多技術(shù)文章,請訪問 OneAPM 官方博客。