1.字典轉(zhuǎn)模型
// MARK: - 內(nèi)部控制方法
private func loadData()
{
NetworkTools.shareInstance.loadStatuses { (array, error) -> () in
// 1.安全校驗(yàn)
if error != nil
{
SVProgressHUD.showErrorWithStatus("獲取微博數(shù)據(jù)失敗", maskType: SVProgressHUDMaskType.Black)
return
}
guard let arr = array else
{
return
}
// 2.將字典數(shù)組轉(zhuǎn)換為模型數(shù)組
var models = [Status]()
for dict in arr
{
let status = Status(dict: dict)
models.append(status)
}
NJLog(models)
}
}
Status.swift
import UIKit
class Status: NSObject {
/// 微博創(chuàng)建時(shí)間
var created_at: String?
/// 字符串型的微博ID
var idstr: String?
/// 微博信息內(nèi)容
var text: String?
/// 微博來源
var source: String?
/// 微博作者的用戶信息
var user: User?
init(dict: [String: AnyObject])
{
super.init()
setValuesForKeysWithDictionary(dict)
}
/// KVC的setValuesForKeysWithDictionary方法內(nèi)部會(huì)調(diào)用setValue方法
override func setValue(value: AnyObject?, forKey key: String) {
NJLog("key = \(key), value = \(value)")
// 1.攔截user賦值操作
if key == "user"
{
user = User(dict: value as! [String : AnyObject])
return
}
super.setValue(value, forKey: key)
}
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
}
override var description: String {
let property = ["created_at", "idstr", "text", "source"]
let dict = dictionaryWithValuesForKeys(property)
return "\(dict)"
}
}
User.swift
import UIKit
class User: NSObject {
/// 字符串型的用戶UID
var idstr: String?
/// 用戶昵稱
var screen_name: String?
/// 用戶頭像地址(中圖)瀑粥,50×50像素
var profile_image_url: String?
/// 用戶認(rèn)證類型
var verified_type: Int = -1
init(dict: [String: AnyObject])
{
super.init()
setValuesForKeysWithDictionary(dict)
}
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
}
override var description: String {
let property = ["idstr", "screen_name", "profile_image_url", "verified_type"]
let dict = dictionaryWithValuesForKeys(property)
return "\(dict)"
}
}
2.UITabelView的相關(guān)方法
extension HomeTableViewController
{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.statuses?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1.取出cell
let cell = tableView.dequeueReusableCellWithIdentifier("homeCell", forIndexPath: indexPath) as! HomeTableViewCell
// 2.設(shè)置數(shù)據(jù)
cell.status = statuses![indexPath.row]
// 3.返回cell
return cell
}
}
HomeTableViewCell.swift
import UIKit
import SDWebImage
class HomeTableViewCell: UITableViewCell {
/// 頭像
@IBOutlet weak var iconImageView: UIImageView!
/// 認(rèn)證圖標(biāo)
@IBOutlet weak var verifiedImageView: UIImageView!
/// 昵稱
@IBOutlet weak var nameLabel: UILabel!
/// 會(huì)員圖標(biāo)
@IBOutlet weak var vipImageView: UIImageView!
/// 時(shí)間
@IBOutlet weak var timeLabel: UILabel!
/// 來源
@IBOutlet weak var sourceLabel: UILabel!
/// 正文
@IBOutlet weak var contentLabel: UILabel!
/// 模型數(shù)據(jù)
var status: Status?
{
didSet{
// 1.設(shè)置頭像
if let urlStr = status?.user?.profile_image_url
{
let url = NSURL(string: urlStr)
iconImageView.sd_setImageWithURL(url)
}
// 2.設(shè)置認(rèn)證圖標(biāo)
if let type = status?.user?.verified_type
{
var name = ""
switch type
{
case 0:
name = "avatar_vip"
case 2, 3, 5:
name = "avatar_enterprise_vip"
case 220:
name = "avatar_grassroot"
default:
name = ""
}
verifiedImageView.image = UIImage(named: name)
}
// 3.設(shè)置昵稱
nameLabel.text = status?.user?.screen_name
// 4.設(shè)置會(huì)員圖標(biāo)
if let rank = status?.user?.mbrank
{
if rank >= 1 && rank <= 6
{
vipImageView.image = UIImage(named: "common_icon_membership_level\(rank)")
nameLabel.textColor = UIColor.orangeColor()
}else
{
vipImageView.image = nil
nameLabel.textColor = UIColor.blackColor()
}
}
// 5.設(shè)置時(shí)間
/**
剛剛(一分鐘內(nèi))
X分鐘前(一小時(shí)內(nèi))
X小時(shí)前(當(dāng)天)
昨天 HH:mm(昨天)
MM-dd HH:mm(一年內(nèi))
yyyy-MM-dd HH:mm(更早期)
*/
// "Sun Dec 06 11:10:41 +0800 2015"
timeLabel.text = "剛剛" //status?.created_at
if let timeStr = status?.created_at
{
// timeStr = "Sun Dec 05 12:10:41 +0800 2014"
// 1.將服務(wù)器返回的時(shí)間格式化為NSDate
let formatter = NSDateFormatter()
formatter.dateFormat = "EE MM dd HH:mm:ss Z yyyy"
// 如果不指定以下代碼, 在真機(jī)中可能無法轉(zhuǎn)換
formatter.locale = NSLocale(localeIdentifier: "en")
let createDate = formatter.dateFromString(timeStr)!
// 創(chuàng)建一個(gè)日歷類
let calendar = NSCalendar.currentCalendar()
/*
// 該方法可以獲取指定時(shí)間的組成成分 |
let comps = calendar.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day], fromDate: createDate)
NJLog(comps.year)
NJLog(comps.month)
NJLog(comps.day)
*/
var result = ""
var formatterStr = "HH:mm"
if calendar.isDateInToday(createDate)
{
// 今天
// 3.比較兩個(gè)時(shí)間之間的差值
let interval = Int(NSDate().timeIntervalSinceDate(createDate))
if interval < 60
{
result = "剛剛"
}else if interval < 60 * 60
{
result = "\(interval / 60)分鐘前"
}else if interval < 60 * 60 * 24
{
result = "\(interval / (60 * 60))小時(shí)前"
}
}else if calendar.isDateInYesterday(createDate)
{
// 昨天
formatterStr = "昨天 " + formatterStr
formatter.dateFormat = formatterStr
result = formatter.stringFromDate(createDate)
}else
{
// 該方法可以獲取兩個(gè)時(shí)間之間的差值
let comps = calendar.components(NSCalendarUnit.Year, fromDate: createDate, toDate: NSDate(), options: NSCalendarOptions(rawValue: 0))
if comps.year >= 1
{
// 更早時(shí)間
formatterStr = "yyyy-MM-dd " + formatterStr
}else
{
// 一年以內(nèi)
formatterStr = "MM-dd " + formatterStr
}
formatter.dateFormat = formatterStr
result = formatter.stringFromDate(createDate)
}
timeLabel.text = result
}
// 6.設(shè)置來源
// "<a href=\"http://app.weibo.com/t/feed/2cEJdS\" rel=\"nofollow\">IT之家</a>"
// 來自: IT之家
if let sourceStr: NSString = status?.source where sourceStr != ""
{
// 6.1獲取從什么地方開始截取
let startIndex = sourceStr.rangeOfString(">").location + 1
// 6.2獲取截取多長的長度
let length = sourceStr.rangeOfString("<", options: NSStringCompareOptions.BackwardsSearch).location - startIndex
// 6.3截取字符串
let rest = sourceStr.substringWithRange(NSMakeRange(startIndex, length))
sourceLabel.text = "來自: " + rest
}
// 7.設(shè)置正文
contentLabel.text = status?.text
}
}
override func awakeFromNib() {
super.awakeFromNib()
// 1.設(shè)置正文最大寬度
contentLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - 2 * 10
}
}
3.MVVM
設(shè)置數(shù)據(jù)
cell.viewModel = statuses![indexPath.row]
// 2.將字典數(shù)組轉(zhuǎn)換為模型數(shù)組
var models = [StatusViewModel]()
for dict in arr
{
let status = Status(dict: dict)
let viewModel = StatusViewModel(status: status)
models.append(viewModel)
}
StatusViewModel.swift
import UIKit
/*
M: 模型(保存數(shù)據(jù))
V: 視圖(展現(xiàn)數(shù)據(jù))
C: 控制器(管理模型和視圖, 橋梁)
VM:
作用: 1.可以對M和V進(jìn)行瘦身
2.處理業(yè)務(wù)邏輯
*/
class StatusViewModel: NSObject {
/// 模型對象
var status: Status
init(status: Status)
{
self.status = status
// 處理頭像
icon_URL = NSURL(string: status.user?.profile_image_url ?? "")
// 處理會(huì)員圖標(biāo)
if status.user?.mbrank >= 1 && status.user?.mbrank <= 6
{
mbrankImage = UIImage(named: "common_icon_membership_level\(status.user!.mbrank)")
}
// 處理認(rèn)證圖片
switch status.user?.verified_type ?? -1
{
case 0:
verified_image = UIImage(named: "avatar_vip")
case 2, 3, 5:
verified_image = UIImage(named: "avatar_enterprise_vip")
case 220:
verified_image = UIImage(named: "avatar_grassroot")
default:
verified_image = nil
}
// 處理來源
if let sourceStr: NSString = status.source where sourceStr != ""
{
// 6.1獲取從什么地方開始截取
let startIndex = sourceStr.rangeOfString(">").location + 1
// 6.2獲取截取多長的長度
let length = sourceStr.rangeOfString("<", options: NSStringCompareOptions.BackwardsSearch).location - startIndex
// 6.3截取字符串
let rest = sourceStr.substringWithRange(NSMakeRange(startIndex, length))
source_Text = "來自: " + rest
}
// 處理時(shí)間
// "Sun Dec 06 11:10:41 +0800 2015"
if let timeStr = status.created_at where timeStr != ""
{
// 1.將服務(wù)器返回的時(shí)間格式化為NSDate
let createDate = NSDate.createDate(timeStr, formatterStr: "EE MM dd HH:mm:ss Z yyyy")
// 2.生成發(fā)布微博時(shí)間對應(yīng)的字符串
created_Time = createDate.descriptionStr()
}
}
/// 用戶認(rèn)證圖片
var verified_image: UIImage?
/// 會(huì)員圖片
var mbrankImage: UIImage?
/// 用戶頭像URL地址
var icon_URL: NSURL?
/// 微博格式化之后的創(chuàng)建時(shí)間
var created_Time: String = ""
/// 微博格式化之后的來源
var source_Text: String = ""
}
HomeTableViewCell.swift
import UIKit
import SDWebImage
class HomeTableViewCell: UITableViewCell {
/// 頭像
@IBOutlet weak var iconImageView: UIImageView!
/// 認(rèn)證圖標(biāo)
@IBOutlet weak var verifiedImageView: UIImageView!
/// 昵稱
@IBOutlet weak var nameLabel: UILabel!
/// 會(huì)員圖標(biāo)
@IBOutlet weak var vipImageView: UIImageView!
/// 時(shí)間
@IBOutlet weak var timeLabel: UILabel!
/// 來源
@IBOutlet weak var sourceLabel: UILabel!
/// 正文
@IBOutlet weak var contentLabel: UILabel!
/// 模型數(shù)據(jù)
var viewModel: StatusViewModel?
{
didSet{
// 1.設(shè)置頭像
iconImageView.sd_setImageWithURL(viewModel?.icon_URL)
// 2.設(shè)置認(rèn)證圖標(biāo)
verifiedImageView.image = viewModel?.verified_image
// 3.設(shè)置昵稱
nameLabel.text = viewModel?.status.user?.screen_name
// 4.設(shè)置會(huì)員圖標(biāo)
vipImageView.image = nil
nameLabel.textColor = UIColor.blackColor()
if let image = viewModel?.mbrankImage
{
vipImageView.image = image
nameLabel.textColor = UIColor.orangeColor()
}
// 5.設(shè)置時(shí)間
timeLabel.text = viewModel?.created_Time
// 6.設(shè)置來源
sourceLabel.text = viewModel?.source_Text
// 7.設(shè)置正文
contentLabel.text = viewModel?.status.text
}
}
override func awakeFromNib() {
super.awakeFromNib()
// 1.設(shè)置正文最大寬度
contentLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - 2 * 10
}
}
4.緩存微博圖片
/// 緩存微博配圖
private func cachesImages(viewModels: [StatusViewModel])
{
// 0.創(chuàng)建一個(gè)組
let group = dispatch_group_create()
for viewModel in viewModels
{
// 1.從模型中取出配圖數(shù)組
guard let picurls = viewModel.thumbnail_pic else
{
// 如果當(dāng)前微博沒有配圖就跳過, 繼續(xù)下載下一個(gè)模型的
continue
}
// 2.遍歷配圖數(shù)組下載圖片
for url in picurls
{
// 將當(dāng)前的下載操作添加到組中
dispatch_group_enter(group)
// 3.3利用SDWebImage下載圖片
SDWebImageManager.sharedManager().downloadImageWithURL(url, options: SDWebImageOptions(rawValue: 0), progress: nil, completed: { (image, error, _, _, _) -> Void in
NJLog("圖片下載完成")
// 將當(dāng)前下載操作從組中移除
dispatch_group_leave(group)
})
}
}
// 監(jiān)聽下載操作
dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in
NJLog("全部下載完成")
self.statuses = viewModels
}
}
5.微博配圖
// 9.1更新cell的尺寸
if itemSize != CGSizeZero
{
flowLayout.itemSize = itemSize
}
// 9.2跟新collectionView尺寸
pictureCollectionViewHeightCons.constant = clvSize.height
pictureCollectionViewWidthCons.constant = clvSize.width
// MARK: - 內(nèi)部控制方法
/// 計(jì)算cell和collectionview的尺寸
private func calculateSize() -> (CGSize, CGSize)
{
/*
沒有配圖: cell = zero, collectionview = zero
一張配圖: cell = image.size, collectionview = image.size
四張配圖: cell = {90, 90}, collectionview = {2*w+m, 2*h+m}
其他張配圖: cell = {90, 90}, collectionview =
*/
let count = viewModel?.thumbnail_pic?.count ?? 0
// 沒有配圖
if count == 0
{
return (CGSizeZero, CGSizeZero)
}
// 一張配圖
if count == 1
{
let key = viewModel!.thumbnail_pic!.first!.absoluteString
// 從緩存中獲取已經(jīng)下載好的圖片, 其中key就是圖片的url
let image = SDWebImageManager.sharedManager().imageCache.imageFromDiskCacheForKey(key)
return (image.size, image.size)
}
let imageWidth: CGFloat = 90
let imageHeight: CGFloat = 90
let imageMargin: CGFloat = 10
// 四張配圖
if count == 4
{
let col = 2
let row = col
// 寬度 = 圖片的寬度 * 列數(shù) + (列數(shù) - 1) * 間隙
let width = imageWidth * CGFloat(col) + CGFloat(col - 1) * imageMargin
// 寬度 = 圖片的高度 * 行數(shù) + (行數(shù) - 1) * 間隙
let height = imageHeight * CGFloat(row) + CGFloat(row - 1) * imageMargin
return (CGSize(width: imageWidth, height: imageHeight), CGSize(width: width, height: height))
}
// 其他張配圖
let col = 3
let row = (count - 1) / 3 + 1
// 寬度 = 圖片的寬度 * 列數(shù) + (列數(shù) - 1) * 間隙
let width = imageWidth * CGFloat(col) + CGFloat(col - 1) * imageMargin
// 寬度 = 圖片的高度 * 行數(shù) + (行數(shù) - 1) * 間隙
let height = imageHeight * CGFloat(row) + CGFloat(row - 1) * imageMargin
return (CGSize(width: imageWidth, height: imageHeight), CGSize(width: width, height: height))
}
extension HomeTableViewCell: UICollectionViewDataSource
{
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel?.thumbnail_pic?.count ?? 0
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("pictureCell", forIndexPath: indexPath) as! HomePictureCell
// cell.backgroundColor = UIColor.redColor()
cell.url = viewModel!.thumbnail_pic![indexPath.item]
return cell
}
}
class HomePictureCell: UICollectionViewCell {
var url: NSURL?
{
didSet
{
customIconImageView.sd_setImageWithURL(url)
}
}
@IBOutlet weak var customIconImageView: UIImageView!
}