当前位置: 首页 > news >正文

内丘企业做网站代刷网站推广

内丘企业做网站,代刷网站推广,新网站建设的工作,广告网站素材欢迎有兴趣的朋友,参与我的美女同事发起的活动《51天吃掉大象》,该美女真的很疯狂,希望和大家一起坚持51天做一件事情,我加入这个队伍,希望坚持51天每天写一篇技术文章。关注她的微信公众号:zhangmanyuheart了解更多吧…

欢迎有兴趣的朋友,参与我的美女同事发起的活动《51天吃掉大象》,该美女真的很疯狂,希望和大家一起坚持51天做一件事情,我加入这个队伍,希望坚持51天每天写一篇技术文章。关注她的微信公众号:zhangmanyuheart了解更多吧。

继续上篇的文章《swift语言之多线程操作和操作队列(上)———坚持51天吃掉大象(写技术文章)》

 

优化我们的程序

目前程序未使用多线程,如果我们仔细分析,会发现有三个耗时的地方,现在我们需要把他们放到其他线程上去,这样主线程就有足够的空间和时间来响应用户操作。 

 

 

根据分析我们可以得知,我们需要一个线程专门响应用户操作,一个线程处理下载数据源和图片,还要一个线程执行添加滤镜操作。

 

我们可以大概的这么去重新构造我的程序设计。我们可以先呈现一个空表格,然后当数据源下载成功后我们刷新表格,刷新表格属于用户操作界面应该放在主线程上。根据数据源内容我们可以知道图片的下载地址,我们最好不要一次性加载所有的图片,这样显然比较耗时,我们只需要知道表中哪些行是用户可以看得到的,然后加载对应行的的图片数据即可,当图片下载完成,程序再呈现图片,再在另外一个线程给图片添加滤镜。这样就完美解决了问题。

 

解决思路可以参看下图表: 

 

我现在只需要重点关注图片处于什么状态,是正在下载还是现在完成,又或者滤镜是否添加?然后给图片添加不同的操作,并且希望用户下拉时,可以取消看不见的表格的相应操作,并开始或恢复用户可见范围的相应操作。因此在这种情况下适合使用NSOperation,而不是GCD。

让我们写代码吧!

首先新建一个swift文件,并命名为PhotoOperations.swift.添加如下代码:

 

import UIKit// This enum contains all the possible states a photo record can be inenum PhotoRecordState {case New, Downloaded, Filtered, Failed}class PhotoRecord {let name:Stringlet url:NSURLvar state = PhotoRecordState.Newvar image = UIImage(named: "Placeholder")init(name:String, url:NSURL) {self.name = nameself.url = url}}

 

这个类用来实现程序的图片展示,并且包含图片所处的状态,默认为.New,代表是新建状态,并有一个默认占位图片。

 

为了了解图片操作的每个状态,我们需要再创建一个类,名称为 PhotoOperations.swift。添加代码:

 

class PendingOperations {lazy var downloadsInProgress = [NSIndexPath:NSOperation]()lazy var downloadQueue:NSOperationQueue = {var queue = NSOperationQueue()queue.name = "Download queue"queue.maxConcurrentOperationCount = 1return queue}()lazy var filtrationsInProgress = [NSIndexPath:NSOperation]()lazy var filtrationQueue:NSOperationQueue = {var queue = NSOperationQueue()queue.name = "Image Filtration queue"queue.maxConcurrentOperationCount = 1return queue}()}

 

 

这个类创建了两个字典,用于记录表格的下载和添加滤镜的操作,以及每个操作的队列。

如你看到的那样,创建队列非常简单。为了调试能查看到队列,最好给队列命名。代码将queue.maxConcurrentOperationCount命名为1,是为让你更直观的看到操作是一个一个执行的。一般我们不需要设置此属性,而交给系统自己决定。系统会根据硬件状态,已经资源占用情况,然后决定给程序多少个线程。

现在添加下载和添加滤镜操作,添加如下代码:

 

class ImageDownloader: NSOperation {//图片类对象
let photoRecord: PhotoRecord//2初始化
init(photoRecord: PhotoRecord) {self.photoRecord = photoRecord}//3重写main方法,执行任务的方法override func main() {//4如果取消操作则不执行if self.cancelled {return}//5下载图片数据
let imageData = NSData(contentsOfURL:self.photoRecord.url)//6再次检查是否取消操作if self.cancelled {return}//7如果获取到了数据,就添加到图片记录中,并将记录标记为.Downloaded,如果没有图片数据就标记为.Failedif imageData?.length > 0 {self.photoRecord.image = UIImage(data:imageData!)self.photoRecord.state = .Downloaded}else{self.photoRecord.state = .Failedself.photoRecord.image = UIImage(named: "Failed")}}}

 

 

NSOperation是一个抽象类,需要继承才能使用,每个子类代表一个具体的任务。

我们继续创建另外一个操作

 

class ImageFiltration: NSOperation {let photoRecord: PhotoRecordinit(photoRecord: PhotoRecord) {self.photoRecord = photoRecord}override func main () {if self.cancelled {return}if self.photoRecord.state != .Downloaded {return}if let filteredImage = self.applySepiaFilter(self.photoRecord.image!) {self.photoRecord.image = filteredImageself.photoRecord.state = .Filtered}}}

 

给ImageFiltration类添加一个应用滤镜的方法:

 

func applySepiaFilter(image:UIImage) -> UIImage? {let inputImage = CIImage(data:UIImagePNGRepresentation(image))if self.cancelled {return nil}let context = CIContext(options:nil)let filter = CIFilter(name:"CISepiaTone")filter.setValue(inputImage, forKey: kCIInputImageKey)filter.setValue(0.8, forKey: "inputIntensity")let outputImage = filter.outputImageif self.cancelled {return nil}let outImage = context.createCGImage(outputImage, fromRect: outputImage.extent())let returnImage = UIImage(CGImage: outImage)return returnImage}

 

 

 

这个方法和在 ListViewController一样,放在这里,就是把把它添加到操作里,方便调用。

 

到此我们创建好工具类了,现在我们开始修改ListViewController.swift。删除lazy var photos属性声明,取而代之添加如下代码:

//保存图片信息数组

var photos = [PhotoRecord]()

//管理状态操作

let pendingOperations = PendingOperations()

 

给该类添加一个方法:

 

 func fetchPhotoDetails() {let request = NSURLRequest(URL:dataSourceURL!)UIApplication.sharedApplication().networkActivityIndicatorVisible = trueNSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {response,data,error inif data != nil {do {let datasourceDictionary = try NSPropertyListSerialization.propertyListWithData(data!, options: NSPropertyListMutabilityOptions.Immutable, format: nil) as! NSDictionaryfor(key,value) in datasourceDictionary {let name = key as? Stringlet url = NSURL(string:value as? String ?? "")if name != nil && url != nil {let photoRecord = PhotoRecord(name:name!, url:url!)self.photos.append(photoRecord)}}self.tableView.reloadData()} catch{print(error)}}if error != nil {let alert = UIAlertView(title:"Oops!",message:error!.localizedDescription, delegate:nil, cancelButtonTitle:"OK")alert.show()}UIApplication.sharedApplication().networkActivityIndicatorVisible = false}}

 

 

 

在viewDidLoad方法中调用这个方法。

fetchPhotoDetails()

 

 

修改 tableView(_:cellForRowAtIndexPath:)的内容,改成如下代码:

 

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {let cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath) as! UITableViewCell//1if cell.accessoryView == nil {let indicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)cell.accessoryView = indicator}let indicator = cell.accessoryView as! UIActivityIndicatorView//2
let photoDetails = photos[indexPath.row]//3
cell.textLabel?.text = photoDetails.namecell.imageView?.image = photoDetails.image//4switch (photoDetails.state){case .Filtered:indicator.stopAnimating()case .Failed:indicator.stopAnimating()cell.textLabel?.text = "Failed to load"case .New, .Downloaded:indicator.startAnimating()self.startOperationsForPhotoRecord(photoDetails,indexPath:indexPath)}return cell}

 

 

 

移除applySepiaFilter方法,替换如下方法:

func startOperationsForPhotoRecord(photoDetails: PhotoRecord, indexPath: NSIndexPath){switch (photoDetails.state) {case .New:startDownloadForRecord(photoDetails, indexPath: indexPath)case .Downloaded:startFiltrationForRecord(photoDetails, indexPath: indexPath)default:NSLog("do nothing")}}

 

 

继续添加如下方法:

fun startDownloadForRecord(photoDetails: PhotoRecord, indexPath: NSIndexPath){//1if let downloadOperation = pendingOperations.downloadsInProgress[indexPath] {return}//2
let downloader = ImageDownloader(photoRecord: photoDetails)//3
downloader.completionBlock = {if downloader.cancelled {return}dispatch_async(dispatch_get_main_queue(), {self.pendingOperations.downloadsInProgress.removeValueForKey(indexPath)self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)})}//4
pendingOperations.downloadsInProgress[indexPath] = downloader//5
pendingOperations.downloadQueue.addOperation(downloader)}func startFiltrationForRecord(photoDetails: PhotoRecord, indexPath: NSIndexPath){if let filterOperation = pendingOperations.filtrationsInProgress[indexPath]{return}let filterer = ImageFiltration(photoRecord: photoDetails)filterer.completionBlock = {if filterer.cancelled {return}dispatch_async(dispatch_get_main_queue(), {self.pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)})}pendingOperations.filtrationsInProgress[indexPath] = filtererpendingOperations.filtrationQueue.addOperation(filterer)}

 

 

我们的重构基本完成,我们运行下看看,会看到如下效果图:

 

 

  

 

注意到了木有,奇迹发生了,图片只在可见的时候才会加载和添加滤镜。并且不会再卡了有木有。

 

继续调优

如果你向下滑动表格,那些从屏幕消失的图片仍在下载或添加滤镜,如果滑动快速的话,程序就会忙着加载图片和添加滤镜了,并占用贷款,影响看见cell的下载了。因此最理想的状态,就是当Cell行消失时,我们停止下载,从而优先下载可见的cell。

 

回到Xcode,修改ListViewController.swift文件,然后找到tableView(_:cellForRowAtIndexPath:)方法,给 self.startOperationsForPhotoRecord(photoDetails, indexPath: indexPath)添加判断:

 

if (!tableView.dragging && !tableView.decelerating) {self.startOperationsForPhotoRecord(photoDetails, indexPath: indexPath)}

 

 

再继续添加如下内容:

override func scrollViewWillBeginDragging(scrollView: UIScrollView) {//1
suspendAllOperations()}override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {// 2if !decelerate {loadImagesForOnscreenCells()resumeAllOperations()}}override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {// 3
loadImagesForOnscreenCells()resumeAllOperations()}func suspendAllOperations () {pendingOperations.downloadQueue.suspended = truependingOperations.filtrationQueue.suspended = true}func resumeAllOperations () {pendingOperations.downloadQueue.suspended = falsependingOperations.filtrationQueue.suspended = false}func loadImagesForOnscreenCells () {//1if let pathsArray = tableView.indexPathsForVisibleRows() {//2
var allPendingOperations = Set(pendingOperations.downloadsInProgress.keys.array)allPendingOperations.unionInPlace(pendingOperations.filtrationsInProgress.keys.array)//3
var toBeCancelled = allPendingOperationslet visiblePaths = Set(pathsArray as! [NSIndexPath])toBeCancelled.subtractInPlace(visiblePaths)//4
var toBeStarted = visiblePathstoBeStarted.subtractInPlace(allPendingOperations)// 5for indexPath in toBeCancelled {if let pendingDownload = pendingOperations.downloadsInProgress[indexPath] {pendingDownload.cancel()}pendingOperations.downloadsInProgress.removeValueForKey(indexPath)if let pendingFiltration = pendingOperations.filtrationsInProgress[indexPath] {pendingFiltration.cancel()}pendingOperations.filtrationsInProgress.removeValueForKey(indexPath)}// 6for indexPath in toBeStarted {let indexPath = indexPath as NSIndexPathlet recordToProcess = self.photos[indexPath.row]startOperationsForPhotoRecord(recordToProcess, indexPath: indexPath)}}}

 

 

 

这已经是最后一步了,恭喜你,也辛苦你了,不过这是值得的,现在你运行看看,一个响应用户及时,并且资源管理合理的程序就在你手上诞生了。注意一下当你滚动表格结束,可见的表格行将马上开始处理操作。 

 

 

转载于:https://www.cnblogs.com/JackieHoo/p/4969309.html

http://www.lbrq.cn/news/2705221.html

相关文章:

  • 完善网站建设的方法百度快速排名优化服务
  • 域名可以绑定网站吗app推广渠道
  • 建设网站遇到的问题深圳网站设计专家乐云seo
  • 公司网站建设设计公司哪家好包头网站建设推广
  • 湖南建设厅网站最佳的搜索引擎
  • 网站建设一样注意什么推广普通话ppt课件
  • 深圳做网站哪家公司好人民日报最新消息
  • 泉州中企网站做的好吗优化疫情二十条措施
  • 灵山招聘网灵山英才网做灵山专业的招聘网站seo关键词排名点击工具
  • 上海专业网站开发怎么买域名自己做网站
  • 网站建设公司发展营销策划方案模板
  • 电脑做任务赚钱网站常德论坛网站
  • 门户类型网站有哪些搜索引擎排名优化公司
  • 台州网站建设方案网络推广方法有哪几种
  • 大学网站开发实验室建设方案企业邮箱怎么开通注册
  • 小米路由器 做网站网站建站价格
  • 调研报告 政府网站建设十种营销方法
  • 华夏望子成龙网站开发背景百度快速收录权限域名
  • 南昌网站忧化网站统计数据
  • 网站维护中页面百度查询最火的关键词
  • 克隆视厅网站怎么做自媒体培训学校
  • 学校学生网站模板下载关键词数据分析
  • 网站推广与电话销售如何结合搜索检索与seo推广
  • 做网站与做软件江北seo综合优化外包
  • ie网站建设买卖平台
  • 企业官方网站建设竞价是什么工作
  • 靠谱的网站制作专业公司海南网站制作
  • 做网站的周记网推接单平台
  • 微信文章同步到wordpress郑州seo顾问热狗hotdoger
  • 颍上县住房和城乡建设局网站爱情链接
  • 上网行为安全概述和组网方案
  • Spring Boot项目调用第三方接口的三种方式比较
  • 公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
  • YOLOv11+TensorRT部署实战:从训练到超高速推理的全流程
  • 把 Linux 装进“小盒子”——边缘计算场景下的 Linux 裁剪、启动与远程运维全景指南
  • 解决程序连不上RabbitMQ:Attempting to connect to/access to vhost虚拟主机挂了的排错与恢复