1.字典转模型
// MARK: - 内部控制方法
private func loadData()
{
NetworkTools.shareInstance.loadStatuses { (array, error) -> () in
// 1.安全校验
if error != nil
{
SVProgressHUD.showErrorWithStatus("获取微博数据失败", maskType: SVProgressHUDMaskType.Black)
return
}
guard let arr = array else
{
return
}
// 2.将字典数组转换为模型数组
var models = [Status]()
for dict in arr
{
let status = Status(dict: dict)
models.append(status)
}
NJLog(models)
}
}
Status.swift
import UIKit
class Status: NSObject {
/// 微博创建时间
var created_at: String?
/// 字符串型的微博ID
var idstr: String?
/// 微博信息内容
var text: String?
/// 微博来源
var source: String?
/// 微博作者的用户信息
var user: User?
init(dict: [String: AnyObject])
{
super.init()
setValuesForKeysWithDictionary(dict)
}
/// KVC的setValuesForKeysWithDictionary方法内部会调用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?
/// 用户认证类型
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的相关方法
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.设置数据
cell.status = statuses![indexPath.row]
// 3.返回cell
return cell
}
}
HomeTableViewCell.swift
import UIKit
import SDWebImage
class HomeTableViewCell: UITableViewCell {
/// 头像
@IBOutlet weak var iconImageView: UIImageView!
/// 认证图标
@IBOutlet weak var verifiedImageView: UIImageView!
/// 昵称
@IBOutlet weak var nameLabel: UILabel!
/// 会员图标
@IBOutlet weak var vipImageView: UIImageView!
/// 时间
@IBOutlet weak var timeLabel: UILabel!
/// 来源
@IBOutlet weak var sourceLabel: UILabel!
/// 正文
@IBOutlet weak var contentLabel: UILabel!
/// 模型数据
var status: Status?
{
didSet{
// 1.设置头像
if let urlStr = status?.user?.profile_image_url
{
let url = NSURL(string: urlStr)
iconImageView.sd_setImageWithURL(url)
}
// 2.设置认证图标
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.设置昵称
nameLabel.text = status?.user?.screen_name
// 4.设置会员图标
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.设置时间
/**
刚刚(一分钟内)
X分钟前(一小时内)
X小时前(当天)
昨天 HH:mm(昨天)
MM-dd HH:mm(一年内)
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.将服务器返回的时间格式化为NSDate
let formatter = NSDateFormatter()
formatter.dateFormat = "EE MM dd HH:mm:ss Z yyyy"
// 如果不指定以下代码, 在真机中可能无法转换
formatter.locale = NSLocale(localeIdentifier: "en")
let createDate = formatter.dateFromString(timeStr)!
// 创建一个日历类
let calendar = NSCalendar.currentCalendar()
/*
// 该方法可以获取指定时间的组成成分 |
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.比较两个时间之间的差值
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))小时前"
}
}else if calendar.isDateInYesterday(createDate)
{
// 昨天
formatterStr = "昨天 " + formatterStr
formatter.dateFormat = formatterStr
result = formatter.stringFromDate(createDate)
}else
{
// 该方法可以获取两个时间之间的差值
let comps = calendar.components(NSCalendarUnit.Year, fromDate: createDate, toDate: NSDate(), options: NSCalendarOptions(rawValue: 0))
if comps.year >= 1
{
// 更早时间
formatterStr = "yyyy-MM-dd " + formatterStr
}else
{
// 一年以内
formatterStr = "MM-dd " + formatterStr
}
formatter.dateFormat = formatterStr
result = formatter.stringFromDate(createDate)
}
timeLabel.text = result
}
// 6.设置来源
// "<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.设置正文
contentLabel.text = status?.text
}
}
override func awakeFromNib() {
super.awakeFromNib()
// 1.设置正文最大宽度
contentLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - 2 * 10
}
}
3.MVVM
设置数据
cell.viewModel = statuses![indexPath.row]
// 2.将字典数组转换为模型数组
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: 模型(保存数据)
V: 视图(展现数据)
C: 控制器(管理模型和视图, 桥梁)
VM:
作用: 1.可以对M和V进行瘦身
2.处理业务逻辑
*/
class StatusViewModel: NSObject {
/// 模型对象
var status: Status
init(status: Status)
{
self.status = status
// 处理头像
icon_URL = NSURL(string: status.user?.profile_image_url ?? "")
// 处理会员图标
if status.user?.mbrank >= 1 && status.user?.mbrank <= 6
{
mbrankImage = UIImage(named: "common_icon_membership_level\(status.user!.mbrank)")
}
// 处理认证图片
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
}
// 处理时间
// "Sun Dec 06 11:10:41 +0800 2015"
if let timeStr = status.created_at where timeStr != ""
{
// 1.将服务器返回的时间格式化为NSDate
let createDate = NSDate.createDate(timeStr, formatterStr: "EE MM dd HH:mm:ss Z yyyy")
// 2.生成发布微博时间对应的字符串
created_Time = createDate.descriptionStr()
}
}
/// 用户认证图片
var verified_image: UIImage?
/// 会员图片
var mbrankImage: UIImage?
/// 用户头像URL地址
var icon_URL: NSURL?
/// 微博格式化之后的创建时间
var created_Time: String = ""
/// 微博格式化之后的来源
var source_Text: String = ""
}
HomeTableViewCell.swift
import UIKit
import SDWebImage
class HomeTableViewCell: UITableViewCell {
/// 头像
@IBOutlet weak var iconImageView: UIImageView!
/// 认证图标
@IBOutlet weak var verifiedImageView: UIImageView!
/// 昵称
@IBOutlet weak var nameLabel: UILabel!
/// 会员图标
@IBOutlet weak var vipImageView: UIImageView!
/// 时间
@IBOutlet weak var timeLabel: UILabel!
/// 来源
@IBOutlet weak var sourceLabel: UILabel!
/// 正文
@IBOutlet weak var contentLabel: UILabel!
/// 模型数据
var viewModel: StatusViewModel?
{
didSet{
// 1.设置头像
iconImageView.sd_setImageWithURL(viewModel?.icon_URL)
// 2.设置认证图标
verifiedImageView.image = viewModel?.verified_image
// 3.设置昵称
nameLabel.text = viewModel?.status.user?.screen_name
// 4.设置会员图标
vipImageView.image = nil
nameLabel.textColor = UIColor.blackColor()
if let image = viewModel?.mbrankImage
{
vipImageView.image = image
nameLabel.textColor = UIColor.orangeColor()
}
// 5.设置时间
timeLabel.text = viewModel?.created_Time
// 6.设置来源
sourceLabel.text = viewModel?.source_Text
// 7.设置正文
contentLabel.text = viewModel?.status.text
}
}
override func awakeFromNib() {
super.awakeFromNib()
// 1.设置正文最大宽度
contentLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - 2 * 10
}
}
4.缓存微博图片
/// 缓存微博配图
private func cachesImages(viewModels: [StatusViewModel])
{
// 0.创建一个组
let group = dispatch_group_create()
for viewModel in viewModels
{
// 1.从模型中取出配图数组
guard let picurls = viewModel.thumbnail_pic else
{
// 如果当前微博没有配图就跳过, 继续下载下一个模型的
continue
}
// 2.遍历配图数组下载图片
for url in picurls
{
// 将当前的下载操作添加到组中
dispatch_group_enter(group)
// 3.3利用SDWebImage下载图片
SDWebImageManager.sharedManager().downloadImageWithURL(url, options: SDWebImageOptions(rawValue: 0), progress: nil, completed: { (image, error, _, _, _) -> Void in
NJLog("图片下载完成")
// 将当前下载操作从组中移除
dispatch_group_leave(group)
})
}
}
// 监听下载操作
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: - 内部控制方法
/// 计算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
// 从缓存中获取已经下载好的图片, 其中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
// 宽度 = 图片的宽度 * 列数 + (列数 - 1) * 间隙
let width = imageWidth * CGFloat(col) + CGFloat(col - 1) * imageMargin
// 宽度 = 图片的高度 * 行数 + (行数 - 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
// 宽度 = 图片的宽度 * 列数 + (列数 - 1) * 间隙
let width = imageWidth * CGFloat(col) + CGFloat(col - 1) * imageMargin
// 宽度 = 图片的高度 * 行数 + (行数 - 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!
}