美文网首页iOS小项目iOS技术资料程序猿的自我修养
自学 iOS - 三十天三十个 Swift 项目

自学 iOS - 三十天三十个 Swift 项目

作者: Allen_朝辉 | 来源:发表于2016-02-13 23:06 被阅读34717次

    整个#30daysSwift 自学计划完全是受到 Sam Lu 的灵感启发,他在 100天内持续学 Swift 写了 40个小项目, 我也是在看了他1月5日发出来的 Medium 文章后立即决定也开始自己的 30天自学计划,每天写一个小项目,如果有天没写也可以在周末的时候多写几个补上。因为其实对 Swift 基础语法并还没有太懂,我是一边看基础语法和一边 Google 一堆网络上的文章或视频 Swift 初学者教程来做项目。

    Sam Lu 并没有把自己的项目代码公开出来,但是我自己还是挺想尝试一下开源,可以给那些也是 Swift 初学者的人一点点「启发」,因为也正是因为「开源精神」,互联网上才会有诸多的「教程」,以下是这30个小项目的 Github 链接

    https://github.com/allenwong/30DaysofSwift


    Project 1 - Simple Stop Watch

    1)NSTimer 来做定时器:NSTimer.scheduledTimerWithTimeInterval;

    2)开始、暂停以及重新计时三个功能;

    Project 2 - Custom Font

    1)看到 @dingyi 在 Twitter 上说,「造字工房」目前授权个人免费非商业使用,所以捐款了1元,下了3款字体用来做试验,分别是造字工房劲黑,致黑和童心;

    2)拖入字体文件.ttf 或 .otf 到工程中,配置 Info.plist - Fonts provided by application, 然后在 Build Phases - Copy Bundle Resources 里增加字体;

    3)需要用到下面一个小技巧来快速查找 FamilyName,找到后就可以使用,Code就可删:

    for family in UIFont.familyNames() {

          for font in UIFont.fontNamesForFamilyName(family) {

               print(font)

          }

    }

    Project 3 - Play Local Video

    1)import AVKit 和 AVFondation,就可以使用系统的视频播放器了;

    2)跟 Project 2里的字体一样,如果要build 在 iPhone 看到视频,那么也需要 Copy Bundle Resources添加下视频资源,这样就行了;

    3)顺便复习了下 UITableView 和 UITableViewCell 的使用方式;

    Project 4 - Snapchat Menu & Camera

    1) Snapchat 的三屏划动很经典,用到 UIScrollView 来实现三屏划动,定义了3个 ViewController;

    2)左和右其实就是个Snapchat 界面截图ImageView,哈哈,所以把 Status Bar 给隐藏了,UIApplication.sharedApplication().statusBarHidden=true;

    3)CameraView 部分有点小复杂,用到了UIImagePickerControllerDelegate里的 API?(不懂该叫什么)

    var captureSession :AVCaptureSession?

    var stillImageOutput :AVCaptureStillImageOutput?

    var previewLayer :AVCaptureVideoPreviewLayer?

    Project 5 - Carousel Effect

    1) 照片横屏划动的旋转木马效果,用 UICollectionViewDataSource 来实现的,每一个卡片是一个 CollectionViewCell;

    2)需要在 Collection View 里的 Scroll Direction 设置为水平滚动;

    3)复习了一遍 Visual Effect View的使用,已经嵌入到 ImageView 里做 clipsToBounds;

    Project 6 - Get user's current location

    1)先实现地理位置权限的获取,需要在 info.plist 里增加 NSLocationAlwaysUsageDescription (输入告知用户为什么要用地理位置权限的原因)和 NSLocationWhenInUseUsageDescription;

    2)导入 CoreLocation Framework,使用 CLLocationManagerDelegate 里的CLPlacemark来获取城市、省份和国家,其实还需要 areasOfInterest,只是不知道为什么没有生效;

    Project 7 - Pull To Refresh and load data

    1)UIRefreshController 来实现下拉刷新,可以改背景色,菊花颜色,文字颜色和大小,attributedTitle的字体颜色困扰了我好久,用到以下方式实现:

    let attributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]

    self.refreshControl.attributedTitle = NSAttributedString(string:"Last updated on\(NSDate())", attributes: attributes)

    2)这次 tableView 都是用代码实现的,所以看过去 Y 轴的位置没有居于 UINavigationBar 之下,但是no-storyboarding 的好处就是学会了 tableView 的很多属性,其实跟 sb 也差不多,对于习惯的人来说确实也非常快,怪不得我之前认识的胖子一直是用代码写 UI,极少用sb;

    3)refreshControl 里的 addTarget 可以做 forControlEvents: .ValueChanged,这样我就可以在下拉刷新的时候把第二组的数据加载出来, This's it!

    4)代码写 UINavigationBar 没法设置 title 啊,topItem,还是 navigationbarItem 都试了;

    Project 8 - Random Color Gradient

    1)我本来想以后做一个 App 可以「听」外界音乐的 beats来进行屏幕背景色的跳动,这样几十台手机一起放在一起,觉得会很震惊,不过我还没这么强可以开发这类应用,所以这次先实现背景渐变色的随机变换,当然也插入了背景音乐,只是没有「听」的功能,效果比较魔性;

    2)学会了用 CAGradientLayer 来做背景的渐变色,渐变色分为两层,后一层决定了整个效果为什么颜色会变化的原因,前面一层是设定好了渐变色颜色、位置和startPoint endPoint;

    3)后一层是实现原理就是随机变化纯色即可,对 RGB三色进行了赋值,比如 redValue = CGFloat(drand48()),这样整个背景颜色可以在256个颜色里随机变化;

    Project 9 - Image Scroller

    1)放大缩小和水平垂直滚动查看图片大图,类似在 iMessage 里查看图片一样的效果;

    2)先是套 UIImageView 到 UIScrollView 里,在 setZoomScaleFor(srollViewSize:CGSize),最大缩放指为原图的3倍;

    3)最后回到最初界面的中心,recenterImage();

    Project 10 - Video Background

    1)一个酷炫的且不是很大的视频作为Splash 界面的背景元素,是足以让用户第一时间感受到这个应用的场景和价值,Spotify 就是个很好的例子,里面用到的素材也是来自 Spotify for iOS;

    2)这次是用了一个自定义 VC: VideoSplashViewController,可以方便的使用到AVPlayerViewController里东西;

    3)fillMode = .ResizeAspectFill,然后就是始终是 loop 的:alwaysRepeat=true;

    4)记得视频文件始终要 copy 到 bundle resources 里去;

    Project 11 - Clear Prioritize TableViewCell

    1)Clear App 的界面和交互非常的惊艳,已经惊艳了好几年了,所以这次想实现一下梯度渐变色的 TableView,当然不仅只是单色,还增加了cell 内的渐变色;

    2)使用以下方法来实现梯度渐变:

    func colorforIndex(index:Int) -> UIColor {

          let itemCount = tableData.count - 1

          let color = (CGFloat(index) / CGFloat(itemCount)) * 0.6

          return UIColor(red:1.0,  green: color,  blue:0.0,  alpha:1.0)

    }

    3)在代码里直接去掉了tableview 的分割线和隐藏了点击 cell 的选中颜色:

    self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None

    cell.selectionStyle = UITableViewCellSelectionStyle.None

    Project 12 - Simple Login Animation

    1)开始学 iOS 动画了,看了基本视图动画,弹性 Spring 动画,关键桢动画以及视图转化,都实在是太有意思了,因为本身我在用 Principle 做原型设计的时候也是用到这些东西,只是此前不知道怎么用代码实现,当然现在也只是刚开始接触,所以学写了一个登录界面过渡动画,已经点击 Login 按钮bounds.size.width+60变宽一下代表 self.loginButton.enabled=false;

    2)viewWillAppear 先设定好2个 UITextField Center.X 约束的初始值,然后才在 viewDidAppear里写 UIView.animateWithDuration(_:, delay:, options:, animations:, completion:),这应该是写动画的过程;

    3)Tips: 一开始没法改 UITextField 的高度,后来是用约束的方式来 Update Frames 实现的;

    Project 13 - Animate TableViewCell

    1)TableViewController 之间的TableViewCell 过场动画,TableViewCell 的梯度渐变之间就采用了 Project-11 里的代码;

    2)tableView 是有visibleCells的,这样可以先在载入前让 Cells不可见,然后到放到界面最底部然后向上载入上来;

    3)这次是用 Spring 动画来实现如此「弹性」的效果:usingSpringWithDamping:0.8, initialSpringVelocity:0,其实也是非常基础的动画;

    Project 14 - Emoji Slot Machine

    1)今天主要是为了 Build for fun,用 UIPickerView 实现了 Emoji 老虎机小游戏;

    2)arc4random( )做随机乱排Emoji,三行三列Emoji;

    3)如果第一列的 Emoji == 第二列 && 第二列 == 第三列,那么就会出现 Bingo!的结果,反之都是💔,GIF演示中的 resultLabel layout 不太对,后来修复了,因为要重新录到三个一样其实概率还是很低的,当然这个概率是可以设定的;

    4)点击 UIButton 的动画效果也在之后完成了,没有出现在这个 GIF 演示中;

    5)分享一个 MacOS 上快速输入 Emoji 的小技巧:按下 Control + Command + 空格键就可以了;

    Project 15 -  Animated Splash

    1)Twitter 的启动动画一直是个经典,小鸟 Logo 居中停留然后放大带出整个界面,是个令人愉悦的过程;

    2)LaunchScreen.storyboard 设定好View 的蓝色背景和放入Twitter 小鸟的图,代码是写在AppDelegate 里的;

    3)区别于原来的 Twitter App 动画,这次是把小鸟当成 Mask 来用,用CAKeyframeAnimation,设定3个Bounds的值,进行过渡就可以实现放大动画。

    let  initalBounds =NSValue(CGRect:mask!.bounds)

    let  secondBounds =NSValue(CGRect:CGRect(x:0, y:0, width:90, height:73))

    let  finalBounds =NSValue(CGRect:CGRect(x:0, y:0, width:1600, height:1300))

    Project 16 - Slide Menu Transition

    1)特别没有使用三条杠的Hamburger icon,而是真用了一个汉堡 Emoji 🍔来做菜单图标:)

    2)2个 VC,用 Segue 做转场,自建 MenuTransitionManagerDelegate 协议,在第一个 VC 里引入,moveDown 到 container!.frame.height -150 这个位置,选中Menu 后第二个 VC 就moveUp 到 -50 的位置;

    3)增加 UITapGestureRecognizer,可以点击非 MenuTableViewCell 部分也可以 dismiss;

    Project 17 - Tumblr Menu

    1)这个是 Tumblr 老版本iOS 内创建新 Post 的转场动画,新版本有了更炫的新动画;

    2)跟 Project 16 一样也是2个 VC,1个 MenuTransitionManager 来实现的,看来这是实现 VC 之间转场动画(同时保留上一层 VC)的「标准方式」?

    3)连了13个 IBOutlet 也是醉了,因为图标和文字都可以按 Delay 时间不同时候出现依次出现,在 MenuTransitionManager 引入 UIViewControllerTransitioningDelegate 来实现动画,包括背景模糊透明透出第一个 VC;

    4)Menu 其实是分为三组,设定 topRowOffset middleRowOffset bottomRowOffset 分别为 CGFloat 300 150 50,所以在 transform 时 Text 和 Photo 为 self.offstage(-topRowOffset) 和 self.offstage(topRowOffset)依次对应,下面2组也是同理;

    5)不过不知道是不是加了背景 Visual Effect View的关系,感觉会「闪」一下,还没有找到办法解决;

    Project 18 - Limit Character

    1)限定 UITextView 输入字符,跟 Twitter 微博一样做140字的限制,然后就无法再输得动了,一开始是 UITextField 尝试,发现不能换行,屁啊,赶紧换到 UITextView 来;

    2)底部一行 UIView 在 viewDidLoad()里做了2个 NSNotificationCenter,通知随着键盘上升和 dismiss;

    3)利用 UITextViewDelegate 里的shouldChangeTextInRange方法来实现输入字符的限制,如果 range.length >140就输入不可用,最右小角的实时字符倒数即使用 "\(140- myTextViewString.characters.count)"来实现;

    4)UI Copy 自第三方 Twitter 客户端 Twitterrific

    Project 19 - Custom Pull-To-Refresh

    1)在 Project 7 时我做了下拉刷新和加载出数据,但是下拉刷新的样式还是系统的菊花样式,所以这次进行自定义下拉刷新的尝试,用单个文字变色旋转和放大的简单动画;

    2)新建RefreshContents.xib 专门来放刷新用的12个 UILabels,不用连接到 ViewController,用 viewWithTag()来指定;

    3)刷新动画分为两步,所以建了2步的方法,animateRefreshStep1() 和 animateRefreshStep2(),第一步是旋转 CGAffineTransformMakeRotation(CGFloat(M_PI_4)) 和 textColor 变随机色 self.getNextColor() (这个是新建的随机色方法),第二步就更为简单了就是做放大动画,全部 Scale 到 CGAffineTransformMakeScale(1.5,1.5);

    4)因为没有真实数据的关系,这个小试验是用 NSTimer.scheduledTimerWithTimeInterval 来稳定5秒做的效果,真实项目里肯定是不用这个的;

    Project 20 - UICollectionView Animation

    1)啊啊啊啊,这个效果其实挺烂的,但是 UICollectionView 的平滑转场我们应该经常看到,特别是 List 和 Details 之间,比如商品列表和商品详情,新闻列表和新闻全文;

    2)这其实是一个 VC,详情界面里只是多了个返回icon,在 func collectionView didSelectItemAtIndexPath 里点击后执行转场动画,把 Cell 带到最前层次 cell?.superview?.bringSubviewToFront(cell!) ,然后 cell?.frame= collectionView.bounds 就可以变大到全屏,通过这个示例也帮助了我理解了 frame 和 bounds 的区别;

    3)在 func backButtonDidTouch() 里记得要让 CollectionView reloadItemsAtIndexPaths 一下;

    Project 21 - Swipeable Cell

    1)滑动Cell 进行相关操作这个交互最经典的应用就是Mailbox 展现的,以至于之后的 iOS 7也引入了系统滑动 Cell 交互,所以可以直接在 tableView editActionsForRowAtIndexPath来自己执行 UITableViewRowAction;

    2)iOS 在设计上的建议是用纯文字来显示,但是我们也可以用图标加文字的方式变得更形象,可惜Google 了一圈还是没找纯粹用自定义的 icon 来代替,所以只能在 title 里加Emoji 和空格来实现,不知道看到的人有什么好的方法;

    let delete = UITableViewRowAction(style: .Normal, title:"🗑\nDelete") { action, indexin}

    3)点击分享的操作调起系统分享控件,是用简单的 UIActivityViewController就可以做到;

    Project 22 - 3D Touch Quick Action

    1)3D Touch 快捷方式是一开始需要在info.plist 里配置 UIApplicationShortcutItems,如下图,我分别配置了我最想要的3个快捷方式,在设置 App 里切换 WiFI,在 NikePlus 里快速开始跑步,照相机里扫描二维码;

    2)UIApplicationShortcutItemIconFile 是配置自定义图标,UIApplicationShortcutItemTitle 配置快捷名字,当然也可以配置二级标题;

    3)选中快捷方式后进入对应的 VC;

    window!.rootViewController?.presentViewController(vc, animated:true, completion:nil)

    Project 23 - Slide Out Menu

    1)手势侧滑菜单进行 VC 之间的切换,使用了 SWRevealViewController 这个开源项目,这让这一切变得真的简单过分了;

    2)侧滑出来的这个 TableViewController 继承了RevealViewController,然后在每一个 VC 的 ViewDidLoad() 里加入如下代码即可进行手势侧滑;

    self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())

    Project 24 - Mosaic Layouts

    1)马赛克照片布局可以调整每行的照片张数等等,用了开源的 FMMosaicLayout

    2)学会了用Terminal 安装 Pod,使用开源项目;

    3)整个布局是明显的 UICollectionView,FMMosaicLayout 支持可计算的 size 变化;

    return  indexPath.item % 7 == 0 ? FMMosaicCellSize.Big : FMMosaicCellSize.Small

    Project 25 - UIView Basic Animations

    1)今天返回学一下动画最基础东西,分别是 Position, Opacity, Scale, Color, Rotation,不管是多酷炫多复杂的动画都是这些基础的累加,本示例里的动画都写在 viewDidAppear() 里;

    2)Position: 3个 UIView 进行位置的移动和高度的改变做了一个 -_- 表情;

    3)Opacity: 改变ImageView 的 alpha 即可;

    4)Scale:  一开始在布 SB 的小一点,然后执行放大Spring动画到 CGAffineTransformMakeScale(2,2), 很明显 alpha 也从0 到1会比较和谐一点;

    5)Color: 改变UIView 和 Label 的 textcolor 即可;

    6)Rotation: 这个有点好玩了,可以做抽奖轮盘的旋转啊,新写了个 func spin() ,在transform的时候 CGAffineTransformRotate(self.rotationImageView.transform,CGFloat(M_PI)),然后在完成动画后再加入 self.spin() 就可以一直不停旋转了,不然选择只会执行一次;

    Project 26 - CoreData App

    1)CoreData 还是挺酷的东西,虽然到现在也不太理解,貌似可以代替数据库的东西;

    2)这个基于 CoreData 的 To Do App 可以增加新的 To-do,删除然后下次打开回来还是跟之前删除之后的一样;

    3)需要在 Coredata 文件里的新建一个实体 ListEntity,和新的item: String 的属性;

    4)记得创建项目或者单个文件的时候一定要勾选 CoreDada;

    Project 27 - Tab Bar Switch

    1)用 TabbarController 加 NavigationController 在 Storyboard 布置下即可实现一个完整的 App 的最基础信息架构的交互,很多App 和数据表明底部的 Tabbar 导航模式比侧滑或者 Android 顶部的导航更让用户接受,几乎不需要写一行代码就可以实现;

    2)为了让整个效果更接近是一个 App,第一个 Tab 的是加入了动态Spring 效果的 TableViewCell,而后面两个 Tab是假的,仅仅只是 UIImageView😂;

    Project 28 - Spotlight Search

    1)iOS 8 之后即可支持在 iOS Spotlight 里搜索第三方应用的数据了,为了做到你的 App 内的数据是 searchable 的,要先新建一个 MoviesData.plist 里配置下数据属性;

    2)在工程 - General - Linked Frameworks and Libraries 里添加 CoreSpotlight 和 MobileCoreServices 框架,这样就可以用使用 CSSearchableItem 的属性了;

    3)在 Spotlight 里的界面也是类似自定义下拉刷新新建的 xib;

    Project 29 - iMessage Image Picker

    1)在App 注册的时候添加头像往往是一个必要的一步,大部分人是直接从相册选个头像的,所以为了方便快速从相册选图使用 iMessage 里照片发送的交互会是个比较好的选择;

    2)在默认头像上加了 Tap Gesture Recognizer,调用相册的方法就在这个 Tap 方法里写,同时需要import Photos,当然做到 iMessage 的交互比较复杂,就直接用了 ImagePickerSheetController 这个开源项目;

    Project 30 - WiKiFace

    1)WiKiFace 是个属于完整功能的Tiny App 了,因为功能就是帮你搜索名人的人名匹配到维基百科的缩略图里的人脸部分,使用到的是维基百科的 API,和 ImageIO 里的 CIFaceFeature;

    2)在 func textFieldShouldReturn() 里执行输入人名后去调 API 里的照片try WikiFace.faceForPerson,WikiFace.swfit 里调到照片后,就需要识别照片里的人脸并且居中;

    3)Is it cool?

    结尾

    应该没有人看到这里吧?因为春节假期和老家网络不太好的关系,文章到现才整理出来(整理的过程其实也 review 了一遍代码)。过去的30天每天都挤出时间写一点代码,这是今年第一个坚持完成的30天挑战计划,接下来会继续看更多的 Swift 基础和接着做一枚 APP。我大部分时候是同步Project 进度信息在 Twitter / Instagram / Dribbble 和 Facebook,有兴趣的人可以关注:)

    相关文章

      网友评论

      • 萌小奇:非常感谢
      • 果冻贱客:哇太感谢了!!!!!!!
      • ed75ee18f6f5:太好啦,一直感觉不知如何入门,这些项目可以好好学习下了,谢谢!!
      • 幻想飞:大佬,我今天开始按你那个那个跟着学,第一个发现 timer=nil 报错 那timer怎么销毁啊 百度也没见swift里面有人提=nil问题
      • snapchat注册:安卓苹果系统通吃!想注册snapchat可以私信我
      • 思念那年慕云:第三个例子,
        在iPhone6真机上运行,
        点击全屏播放的时候崩溃了
      • 小白谈理财:我的哥 这个在xcode9.1上不能跑,是因为swift版本问题吗?
      • afb842417004:厉害了,
      • 背靠背的微笑:我在github上下载了安装包,解压不成功。:joy:
      • brzhang:昨天全部过了一遍,真不错
      • 像个被吓坏的孩子:project 4 会崩掉 不知道什么原因
        CameraView中
        captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080
        没打印任何东西,模拟器一片白
      • Pusswzy:3.0出来了 可以开始学了
        Allen_朝辉:@Pusswzy Github 上已经有升级到3.0版本了。
      • 春不语:66666666
      • 像个被吓坏的孩子:赞 楼主好人,以后发大财😊
      • c33590a5dedf:可以分享一下代码吗?我最近也在自学swift
        Allen_朝辉:@流淌的瞬间 仔细看文章哦,最前面就有 github 链接的。
      • 1d1146c7943d:谢谢分享!
      • sara_org:好好玩。。。 :blush:
      • zyz空格:收藏了,谢谢。如果能把这些教程的地址公开一下就更棒了!
        Allen_朝辉:@zyz空格 在 Github 的 ReadMe 里有的 https://github.com/allenwong/30DaysofSwift
      • zhiyi:请问真机用什么工具录屏,模拟器我是用qtime
        zhiyi:@Allen_朝辉 screenFlow也可以在手机上录吗?还是说只是录模拟器?
        Allen_朝辉:@zhiyi ScreenFlow -> video, Gifrocket -> GIF
      • 改变自己_now:赞:+1:🏻赞
      • 程序员Wiseman:两千多star了,神速
      • SingorZhu:你是不是参照那个人的项目,然后自己去找实现的方法?
        Allen_朝辉:@SingorZhu 部分参照,没有太多,是的Google 了很多教程。
      • 2ed95b412105:想请教一下几个问题:
        1.您看的Swift教程是什么?
        2.Swift能不能胜任iOS开发?有没有遇到还是得用OC的情况?
        8bb06eb34638:@gzztz 个人觉得现在要就业的话还是学OC吧,虽然我觉得楼主的这些Demo很炫很让人羡慕,如果现在Swift就能完全替代OC的市场地位的话,我肯定跟着这个教程学iOS了
        Allen_朝辉:@gzztz 1、在我的 Github ReadMe 里有提到哦,以及链接;
        2、Swift 当年做完整的 App,因为是初学者的关系,我还法回答后面的问题呢,有些我个人觉得还是需要的,比如用到别人的 OC 开源库。
      • 袁赋豪:赞!
      • SingorZhu:我决定紧跟楼主的步伐
        Allen_朝辉:@SingorZhu 没有,我是个设计师。
        SingorZhu:@Allen_朝辉 你是之前有OC的开发经验吧?
        Allen_朝辉:@SingorZhu Awesome!
      • 落北风:希望自己也能一样
      • 不闹海就闹心的哪吒:虽然看不太懂,但还是觉得好厉害!
      • b5e6d2321594:谢谢分享,有福了
      • 庸者的救赎:去看看iOS 9 APP develop essential,不错的iOS入门
        zhenxingdev:@庸者的救赎 有网址吗
      • 暮落晨曦:赞:+1:🏻,学习了!
      • b717571476a2:我看完了。对于不知道要怎么学习iOS的我来说是一种启发,决定向楼主学习,写小Demo,想以楼主的项目做原型写不知道可不可以,不过我是写oc。谢谢楼主
      • 大灰灰iOS:楼主好棒。准备照着楼主的这个也敲一遍。老是觉得自己忙啊什么的,学swift不能再拖了,多谢楼主么么哒~
        Stone三石哥:@大灰灰iOS 大神灰灰,坐等文章更新哈
        大灰灰iOS:@devyul 灰灰表示现在压力很大。。。
        Stone三石哥:@大灰灰iOS 灰灰也出个swift的学习记录
      • 春和花香:请问楼主用的什么工具做的gif图?
        Allen_朝辉:是手机连接 Mac,ScreenFlow录屏,然后用 GIFRocket 将视频转成 GIF.
        春和花香:@TomorJM thx
        58f0b442f46c:@春和花香 推荐你一个 liceCap
      • 死神一护:必须感谢楼主大大的来源

      本文标题:自学 iOS - 三十天三十个 Swift 项目

      本文链接:https://www.haomeiwen.com/subject/wddfkttx.html