当前位置: 首页 > 科技观察

开发App的正确步骤是什么?

时间:2023-03-16 17:03:50 科技观察

在iOS开发中,写一个App很容易,但是要写出一个好的App却需要付出很大的努力。首先我们看一个App的开发需求:写一个App,展示Spotify上所有LadyGaga相关的音乐专辑。相关信息可以在以下网址找到:https://api.spotify.com/v1/search?q=lady+gaga&type=album需求分析首先拿到开发需求,最重要的是明确开发细节。有很多东西我们不知道,需要跟产品经理和设计师沟通:用TableView还是CollectionView来展示?每张音乐专辑需要显示什么信息?如果相册太多,我们应该先显示哪些相册?这个App除了显示信息外,还需要哪些扩展功能?这个产品尺寸有要求吗?需要多少天才能完成?经过讨论,大家一致同意做如下App:LadyGaga,所以我们知道有必要做一个tableView,每个Cell对应一个专辑信息,左边是图片,右边是专辑名。点击单元格,可以看到对应的相册大图。构建架构首先这个app比较简单,我们只需要使用最基本的MVC就可以做好。Model部分:只需要一个Model,就是Album,对应每个专辑的信息;View部分:主要部??分可以在Storyboard中完成;***单独创建一个UITableViewCell的子类,对应设置相册的UI;ViewController部分:其中一个ViewController是TableViewController,负责展示所有相册的信息;另一个ViewController负责显示详细信息,比如相册的大图;网络部分:负责从网上抓取专辑信息;并根据相册的图片URL获取图片数据;基本架构细节实现网络部分:fetchAlbums和downloadImage可以用Apple自带的URLSession和JSONserialization实现,也可以使用优秀的第三方库AlamoFire。因为这个app比较简单,AlamoFire的优势不明显,引入第三方库会增加app的体积,所以推荐前者。基本上实现了以下两个函数:对于***A函数fetchAlbums,由于网络请求是一项耗时耗力的工作,所以我们一般使用后台线程而不是主线程(UI线程)来处理,以保持UI的流畅运行。Closure用于异步多线程完成后回调,error用于监控网络请求是否有误。对于第二个函数downloadImage,最简单的方法就是通过url获取对应的数据,然后通过对应的数据获取图片。之所以返回optional是因为可能是url有问题或者网络请求有错误,此时返回nil。从API设计的角度来看,上面的downloadImage并不是最好的设计。最好的设计是我们可以知道哪里出错了,比如下面这样:letdata=tryData(contentsOf:aUrl)ifletimage=UIImage(data:data){returnimage}else{throwDownloadImageError.InvalidData}}catch{throwDownloadImageError.InvalidURL}}ViewController部分:对于AlbumsController,我们使用代理模式(Delegate),即关于AlbumsController的tableView代理。我们只需要实现相应的dataSource和delegate方法即可。对于数据源,有两个方法必须实现。它们是:functableView(_tableView:UITableView,numberOfRowsInSectionsection:Int)->IntfunctableView(_tableView:UITableView,cellForRowAtindexPath:IndexPath)->UITableViewCell同时,在AlbumsController中,有两个数组,一个是专辑([Album])和一个是图片([UIImage?]),这样我们只需要下载一次数据存到对应的数组中,之后就不需要再做网络请求的相关工作了。也就是说,这两个数组起到了缓存的作用。具体实现是:先请求服务端去取viewDidLoad()中对应的数据。然后根据相册的数量设置对应的TableView的行数。在具体的一行中,我们可以根据indexPath来确定对应的相册。根据对应相册的图片URL,我们可以得到对应的图片,然后缓存到图片数组中。由于我们复用了TableView的Cell,如果不缓存图片,每次都去网络请求,会因为延迟严重导致图片闪烁。***两个ViewController之间的跳转可以用navigationController实现。查看部分:自定义AlbumCell可以保证App的扩展性很好。同时为了解决部分相册名称过长导致Label无法显示的问题,可以使用autoshrink来处理。App运行流程优化和扩展上面的设计和实现很理想,现在我们要考虑一个临界情况,如果网络不稳定,我们应该怎么办?一个简单的解决方案就是在网络好的时候下载数据,存放在缓存和存储中,即使网络中断或者App崩溃,我们也可以从存储中获取相应的数据。这里引入Facade,新建一个类LibraryAPI,提供两个接口:这里的方法和前面的Network不同的是,getAlbums方法会先尝试从storage中获取对应的数据,如果没有就去访问Network,然后将从Network中获取到的值存储到storage中。这里的实现有点复杂,涉及两大模块和多线程操作,但是我们不用关心方法内部的实现,只关心接口,这就是外观模式的优势。同时,LibraryAPI类最好使用单例模式(singleton),因为它应该被看作是一个全局的API,被各个ViewController访问,这样的设计也节省了资源。优化App流程的另一个优化点是,如果我们一开始拿到的数据很多——比如10000张专辑,应该怎么操作?正确的方法是分页。我们可以先只取20个并将它们显示在TableView上。当用户快要滑到底部的时候,我们可以再取20个,然后内存中总共可以显示40个,以此类推。这样做的好处是我们不需要下载所有数据,以最快最流畅的方式对TableView进行布局,同时根据用户的需求增加相应的相册数据。***一个优化点是,如果用户快速上下滑动,我们如何以最快的速度加载图片?答案是使用operationQueue来处理。当当前单元格可见时,我们恢复下载图片的过程,否则我们暂停。这样可以保证我们用有限的内存和CPU来高效的下载用户需要的和当前想看的图片。值得一提的是,你还可以借鉴ASDK的思路,进一步优化程序。总结本文从一个简单的tableViewApp入手,讲述了开发一个App的四个步骤:需求分析、构建架构、详细实现、优化扩展。多线程和几种设计模式的简单介绍,希望对大家有所帮助。