iOS 入门开发踩坑实录

其实人生也没有什么道理可讲,但是我们不必丧气,还是要期待,人生有奇遇。

前言

苹果开发者:iOS Developer

最近因为工作需要要开始搞iOS了,简单记录下我收集和学习的过程。

学习资料准备

组里大佬给我推荐的资料:

地址 说明
人机交互指南 快速看完这个人机交互指南,对iOS系统有个概念。
旧版Sample 有很多可以快速入门的Sample。
官方文档 官方的文档,可以快速检索。
官方OC教程 可以看看了解下OC的基本语法。
Swift官方文档 The powerful programming language that is also easy to learn.
Swift UI官方手把手教学 这是一份手把手教学的文档,很适合新手开发,了解Swift UI的开发和使用流程。

大佬给我的意见是先看完人机交互指南,了解iOS开发和Android开发的区别,看完之后再看看旧版Sample,从Sample中学习Objective-c的语法和iOS的开发流程。

  1. 第一天:看完之后的大概想法就是,了解一门新的技术的开发理念对于开发符合该技术理念的产品十分有帮助,不至于开发出一个不伦不类的产品出来,也可以与系统比较和谐。
  2. 第二天:了解了基本的Objective-C语法和一部分的Swift的语法,不过还是一脸懵……没有太多集中的时间可以学习。
  3. 第三天:这份文档Swift UI官方手把手教学是入门Swift UI的最快速的流程,图文形式展示了Swift UI的开发流程;B站的iOS编程建议教程真香,比官网的Sample简单移动多了……

基础文章

Objective-C

文章 说明
Objective-C Objective-C的基础语法WIKI介绍。
Objective-C 入门教程 简单容易理解的Objective-C的基础教程。
苹果开发者文档·中文版 一份半成品的中文版开发文档,可以简单看看。
语法基础——Objective-C语法基础 比较简单的介绍了OC的一些语法和注意事项。
let 定义常量,用let的原因可见于:A Guide to Writing Mathematics,见第10页:Defining variables and formulas。
谈谈 Objective-C 链式语法的实现 类似于Java的建造者模式,可以大大的简化代码,提高可读性和接口易用性。

Swift

文章 说明
Swift官方文档 The powerful programming language that is also easy to learn.
Swift教程 一个极其简单的Swift语法入门教程。
Swift 函数参数前的“_”是什么意思? 比如func someFunction(_ firstParameterName: Int, secondParameterName: Int)中的_表示调用的时候可以忽略参数名称,someFunction(1, secondParameterName: 2)
官方基础工程简介 2019 Version 11.1 (11A1027)【2019】的Xcode创建的工程目录结构介绍,以及SceneDelegate生命周期会掉方法的介绍、ContentView的介绍。
Swift3.0语法变化 对比介绍了Swift 3.0和Swift 2.0的区别,有助于了解语言的发展历史。

Swift UI

Swift UI官方手把手教学——这是一份手把手教学的文档,很适合新手开发,了解Swift UI的开发和使用流程。

小知识点

常用的宏定义

也不知道用不用得着,暂时放着,不整理了。

静态库与动态库

文件操作

学习视频

不得不说,Bilibili果然是一个学习的好地方……╮(╯▽╰)╭

视频 说明
【爱学啊】快速入门iOS Swift编程开发 Swift OC Objective-C Xcode 0基础 入门 强烈安利看看,这个很适合快速了解Storyboard是如何使用「拖一拖」的神仙操作完成界面设计的过程。

一些OC的知识点理解

文章 说明
id类型和instancetype类型 介绍OC的id类型和instancetype的类型的区别。
iOS·NSObject的两种含义:类与协议 介绍了类与协议,并介绍如何通过协议实现多继承
@selector()的原理 理解OC中方法的创建和查找的创建过程。也推荐阅读iOS套路面试题之Selector的文末部分,更深入的分析推荐阅读:深入理解Objective-C:方法调用
关于方法的「+」和「-」 -方法是实例方法,放在类的结构空间的方法列表中,而+方法是类方法。
iOS开发中方法延迟执行的几种方式 四种延迟执行的方法比较与说明
@property 参数详解 strong:强引用;week:弱引用;copy:每次生成一个实例,防止Mutable对象被修改;nonatomic:非原子性;atomic:原子性……
OC学习笔记十四 构造函数 如何自定义构造函数的多种方式。
oc 16进制字符串与10进制的转换 两行代码搞定 10进制转换为16进制:NSLog(@"%ld",strtoul([@"0000c376" UTF8String],0, 16));
Int转NSString的高大上写法 NSString *string = @(number).stringValue;
CRC校验32位,提供给iOS使用 扩展NSData,实现crc32校验。
iOS-如何优雅的隐藏主页面的导航栏,而只展示详细页面的导航栏(UINavigationBar) 如何显示和隐藏UINavigationBar的操作。

关于NS*等库前缀的解释

下述段落摘抄于:IOS开发之-NS**概述

在iOS开发中,经常会遇到NS开头的对象,这个要从乔帮主历史恩怨说起。当年Steve Jobs 和John Scullery与恩怨,乔帮主当年被人挤兑出苹果,自立门户的时候做了个公司叫做NextStep,里面这一整套开发包很是让一些科学家们喜欢,而现在Mac OS用的就是NextStep这一套函数库。

这些开发NextStep的人们比较自恋地把函数库里面所有的类都用NextStep的缩写打头命名,也就是NS了。比较常见的比如:NSLog、NSString、NSInteger、NSURL、NSImage……

Historical Note: If you’re wondering why so many of the classes you encounter have an NS prefix, it’s because of the past history of Cocoa and Cocoa Touch. Cocoa began life as the collected frameworks used to build apps for the NeXTStep operating system. When Apple purchased NeXT back in 1996, much of NeXTStep was incorporated into OS X, including the existing class names. Cocoa Touch was introduced as the iOS equivalent of Cocoa; some classes are available in both Cocoa and Cocoa Touch, though there are also a large number of classes unique to each platform.
Two-letter prefixes like NS and UI (for User Interface elements on iOS) are reserved for use by Apple.

前缀 说明
NS NextStep
UI for User Interface elements on iOS

OC和Swift的gitignore配置

调试

进阶

Ruby

工欲善其事必先利其器,Cocoapod基于Ruby,需要先把环境搭建好(Mac自带,不需要安装了)

Ruby国内源

gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ 

Gem

常用指令 说明
gem sources -l 查看源地址
gem sources -u 更新缓存
gem sources --add 源地址 添加源
gem sources --remove 源地址 删除源

Pod的使用

Pod是CocoaPods提供的功能,详见开源项目:CocoaPods

文章 说明
Podfile 解析最佳实践 介绍Podfile的原理和Ruby的语法。
Pods的static_framework使用感受 介绍podspec的s.static_framework=true的使用及其优缺点。Tips:如果依赖的库是某个库的静态库,也就是framework,则需要在.podspec文件中的添加依赖前进行指明s.static_framework=true
使用cocoapods打包静态库(依赖私有库,开源库,私有库又包含静态库) 详细的介绍了Podspec的配置和使用。
使用Podspec的subspec实现组件的按需引用 按需引用Pod中的某一部分。
使用私有Cocoapods仓库 中高级用法 私有Pods的创建流程及PodSpec的配置流程讲解。

Podfile配置

配置 说明
inhibit_all_warnings! 屏蔽Cocoapods库里面的所有警告。
use_frameworks! 在Pods中用frameworks替代静态库。
source 'https://github.com/CocoaPods/Specs.git' 使用公有库,支持使用私有库,修改地址即可。

附上一个PodSpec逐字解析:

Pod::Spec.new do|s|
  # 项目名称
  s.name             = 'YourPodName'
  # 版本
  s.version          = '0.1.0'
  # 简介
  s.summary          = 'A short description of YourPodName.'
  # 详细介绍
  s.description      = "详细介绍"
  # 项目主页
  s.homepage         = "https://github.com/xxx/YourPodName"
  # 截图                      
  s.screenshots      = "www.example.com/screenshots_1"
  # 支持的协议及文件
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  # 作者名字和邮箱
  s.author           = { 'skx926' => '[email protected]' }
  # 仓库地址
  s.source           = { :git => 'https://github.com/skx926/YourPodName.git', :tag => s.version.to_s }
  # 社交媒体地址
  s.social_media_url = 'https://twitter.com/xxx'  
  # 最低要求的系统版本
  s.ios.deployment_target = '8.0'
  # 源文件路径
  s.source_files = 'YourPodName/Classes/**/*'
  # 资源文件存放位置
  s.resource_bundles = {
    'YourPodName' => ['YourPodName/Assets/*.png']
  } 
  # 暴露给外部的头文件
  s.public_header_files = 'YourPodName/Classes/**/*.h'
  # 项目中使用的系统framework
  s.frameworks = 'UIKit', 'MapKit'
  # 项目中使用的第三方framework
  s.vendored_frameworks = 'Thirdparty.framework'
  # 项目中使用的系统静态库
  s.libraries = 'iconv', 'xml2'
  # 项目中使用的第三方静态库
  s.vendored_libraries = 'Library/gmssl/*.a'
  # Xcode配置
  s.xcconfig = { "HEADER_SEARCH_PATHS" => "${PODS_ROOT}/../../Library/gmssl"}
  # 项目依赖的第三方库
  s.dependency 'AFNetworking', '~> 2.3'
end

源于:SDK开发和打包静态库遇到的坑,SubSpec请见:podspec文件解析

Pod版本参数

参数 说明
pod ‘模块名’ 不显式指定依赖库版本,表示每次都获取最新版本
pod ‘模块名’, ‘2.0’ 只使用2.0版本
pod ‘模块名’, ‘> 2.0’ 使用高于2.0的版本
pod ‘模块名’, ‘>= 2.0’ 使用大于或等于2.0的版本
pod ‘模块名’, ‘< 2.0’ 使用小于2.0的版本
pod ‘模块名’, ‘<= 2.0’ 使用小于或等于2.0的版本
pod ‘模块名’, ‘~> 0.1.2’ 使用大于等于0.1.2但小于0.2的版本
pod ‘模块名’, ‘~>0.1’ 使用大于等于0.1但小于1.0的版本
pod ‘模块名’, ‘~>0’ 高于0的版本,写这个限制和什么都不写是一个效果,都表示使用最新版本

Pod命令

命令 说明
pod install 只会安装Podfile中新改变的东西,不会更新那些已经安装了的库。优先遵循 Podfile 里指定的版本信息;其次遵循Podfile.lock里指定的版本信息来安装对应的依赖库。
pod install --verbose --no-repo-update 不更新本地Spec仓库,直接拉取更新。
pod update 根据Podfile的规则更新所有依赖库,Podfile.lock无效,且会生成新的文件来覆盖原来的。
pod update --verbose --no-repo-update 不更新本地Spec仓库,直接拉取更新。
pod repo update 用来更新本地cocoapods的spec资源配置信息。
pod cache list 查看所有spec文件的缓存,可以直接到路径下删除文件
pod cache clean AFNetworking 删除指定库的缓存文件
pod ipc spec --help 将pobspec转化为podspec.json

Pod产物及部分说明

产物 说明
Podfile.lock 初次执行pod install时产生,包含依赖库的版本号。
Manifest.lock Manifest.lock 是 Podfile.lock 的副本。每次只要生成 Podfile.lock 时就会生成一个一样的 Manifest.lock 存储在 Pods 文件夹下。项目 Build 的时候,会检查一下 Podfile.lock 和 Manifest.lock 是否一致。
Spec Repo 存放 Spec 文件的仓库,所有公开的 Pods 都在这个里面,是一个Git仓库 remote 端。执行 pod setup命令会clone 该仓库 到本地的~/.cocoapods/repos目录下。仓库保存了依赖库的名称,版本号,以及spec文件。

其他

编译产物及其对比

产物 说明 缺点
静态库*.a 编译时将库编译到目标程序中。 包体积变大。
动态库*.dyld 编译只存储了指向动态库的引用,多个程序可共用,在运行时加载,不会使包体积变大 运行时加载会损耗部分性能,并且依赖外部环境,如果库不存在或者版本不正确则无法运行。
Framework 实际上只是一种打包方式,将库的二进制文件、头文件和有关的资源打包到一起,方便管理与分发。

对比:

  • 用Cocoapods 导入Swift 框架到Swift项目和OC项目都必须要use_frameworks!
  • 用动态库,必须要在Podfile文件中添加use_frameworks!
  • 如果在Podfile文件里不使用use_frameworks!则是会生成相应的*.a文件(静态链接库),通过Static Libraries这个方式来管理Pod的代码。
  • 如果使用了use_frameworks!则Cocoapods 会生成相应的*.frameworks文件(动态链接库:实际内容为Header+动态链接库+资源文件),使用Dynamic Frameworks 来取代Static Libraries方式。
  • Linked:libPods-xxx.a包含了其它用pod导入的第三方框架的*.a文件。
  • Linked:Pods_xxx.framework包含了其它用pod导入的第三方框架的*.frameworks文件。

多工程依赖

组件化

文章 说明
iOS组件化之私有库 讲解了建立私有pod仓库,以及代码解耦分pod的方式。
基于 CocoaPods 的组件二进制化实践 火掌柜 iOS 客户端经过近两年的组件化推进,组件数量已经颇具规模,达到了近 100 个。随着组件数量和代码量越来越多,主工程的打包时间从最初的十几分钟,增加到了现在的四十分钟左右。依赖组件较多,改动相对频繁的上层业务组件,其发布时间也较为漫长。编译时长的困扰,已经明显影响了日常开发体验,同时也造成 CI pipeline 执行时间过长,在 runner 资源匮乏的情况下,不利于内部 CI 的推广。当前时间节点下,如何减少编译时长,已经成为开发团队较为迫切的需求。

开发工具

Xcode

虚拟机快捷键

键位 说明
command+方向键 模拟器屏幕旋转
command+shift+h home键操作
command+s 模拟器截图
command+shift+c 复制模拟器截图到剪贴板
command+L 模拟器锁屏

动态库链接

链接 说明
target depnedencies 编译前,告诉工程在运行的时候先去编译这里导入的库。
Link Binary With Libraries 编译时期,添加某个project需要链接的库,会被编译到工程的包里。
Embedded Binaries 运行时,告诉app运行时去哪些库里找实现方法。
  • 当你导入一个库时,Target Dependencies和Link Binary With Libraries两个选项都必须设置。只有可运行的Project里需要设置Embedded Binaries。
  • 当你引入一个静态库的时候,由于静态库不需要编译,只需要设置Link Binary With Libraries选项即可。
  • 当你Embedded一个库时,Xcode会自动配置Target Dependencies和Link Binary With Libraries。

包管理

Cocoapods的使用介绍:Cocoapods

推荐一些常用的配置方式

强烈推荐这个教程:Podfile文件用法详解

  • 配置Cocoapods库的地址
source 'https://github.com/CocoaPods/Specs.git'
  • 抑制依赖的Warnning
# 忽略引入库的所有警告
inhibit_all_warnings!
  • 添加私有源
repo add PodSpec名称 http://xxx/xxx/PodSpec.git
  • 更新源:pod repo update

  • 导入依赖

# 拉取最新版本的依赖
pod 'project'
# 拉取指定版本的依赖
pod 'project', '1.2.3'
# 在指定配置下拉取依赖
pod 'project', :configuration => 'Debug' # 一个配置
pod 'project', :configurations => ['Debug', 'Release'] # 多个配置
# 拉取子模块
pod 'project/subProject' # 单个子模块
pod 'project', :subspecs => ['subProject1', 'subProject2'] # 多个子模块
# 拉取本地的依赖
pod 'project', :path => '~/Library/project'
# 拉取远程的版本
pod 'project', :git => 'https://github.com/notzuonotdied/project.git' # 默认是master分支
pod 'project', :git => 'https://github.com/notzuonotdied/project.git', :branch => 'dev' # 指定dev分支
pod 'project', :git => 'https://github.com/notzuonotdied/project.git', :tag => '1.2.3' # 指定tag
pod 'project', :git => 'https://github.com/notzuonotdied/project.git', :commit => '123456' # 指定commit ID
# 拉取其他podspec的源
pod 'project', :podspec => 'https://gitlab.com/project.podspec'

查看模拟器沙盒文件

  • 模拟器所在文件夹:/Users/username/Library/Application Support/iPhone Simulator
目录 说明
Documents 苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录。
Library 存储程序的默认设置或其它状态信息。
Library/Caches 存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除,当手机的内存不足是会删除该目录下的文件。
tmp 提供一个即时创建临时文件的地方。
  • iTunes在与iPhone同步时,备份所有的Documents和Library文件。
  • iPhone在重启时,会丢弃所有的tmp文件。
  • App Data目录:/Users/username/Library/Developer/CoreSimulator/Devices/cryptic number/data/Containers/Data/Application/cryptic number
    • 第一个cryptic number:虚拟机的序列号。
      • 即:Windows -> Device and Simulator -> Simulator -> Identifier
    • 第二个cryptic number:安装在虚拟机的序列号。
      • 这个需要用代码或者是用tree输出查找。
      • 使用brew cask install tree安装tree命令。

查看真机沙盒文件

  • Windows-Devices and Simulators
  • Devices-选择设备-点击Installed Apps下任意一个App-设置按钮
    • Download Container:下载应用沙盒到本机
    • 鼠标右击-显示包内容:这样子就可以查看应用沙盒的内容了

详见:iOS开发 查看真机沙盒文件

开发

开发规范

CI/CD

代码覆盖测试

OC

OC可以使用Gcov进行代码覆盖测试

  • Gcov主要支持Objective-C
  • 适合大部分代码为OC语言编写的项目

项目集成

  • 设置Generate Legacy Test Coverage Files为Yes
  • 设置Instrument Program Flow为Yes

代码配置

AppDelegate.mdidFinishLaunchingWithOptions中配置如下代码:

- (void)applicationDidEnterBackground:(UIApplication *)application {
//#if NT_COVERAGE
#if !TARGET_IPHONE_SIMULATOR
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    setenv("GCOV_PREFIX", [documentsDirectory cStringUsingEncoding:NSUTF8StringEncoding], 1);
    setenv("GCOV_PREFIX_STRIP", "13", 1);
#endif
    extern void __gcov_flush(void);
    __gcov_flush();
//#endif
}

在需要采集覆盖率的地方加入代码

extern void __gcov_flush(void);
__gcov_flush();

iOS知识点

知识点 说明
iOS应用程序的生命周期 介绍iOS应用程序的架构(MVC)和生命周期。
iOS开发 生命周期 这篇文章关于iOS的生命周期的介绍比较直观。
iOS 中静态链接库的使用 介绍Framework和*.a文件。

开源库

说明
ZipArchive 解压缩,工程的配置详见:SSZipArchive
iOS 数据压缩与解压 gzip解压缩oc代码。

上手优秀的工程

踩坑实录

收集一些遇到的问题以及解决方案。

No such module ‘Alamofire’

Always get build error : No such module 'Alamofire’的解决方案:Make sure you have opened the “project_name”.xcworkspace instead of “project_name”.xcodeproj .As you are working on pods all the installed pod will be available only in your .xcworkspace project file.

  • 翻译下:大概是因为你打开工程的方式是选择了 .xcodeproj 后缀的文件,而不是使用 .xcworkspace 后缀的文件,导致依赖的pod库都没有导入成功……╮( ̄▽ ̄)╭
  • 解决方案:进入工程根目录,使用 .xcworkspace 打开工程……

(不得不说,我看到这个答案,我的内心是崩溃的……)

pod install拉取慢

pod installpod update慢可以使用下面的指令:

pod install --verbose --no-repo-update
pod update --verbose --no-repo-update

not in the window hierarchy

问题:Attempt to present UIViewController on UIViewController whose view is not in the window hierarchy
解决方案:

  • For Display any subview to main view,Please use following code
UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}
[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];
  • For Dismiss any subview from main view,Please use following code
UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}
[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];

判断NSString为空容易犯的错

  • 具体可以看看这个文章:查看

Xcode 10 Error: Multiple commands produce

问题描述:Xcode 10使用了新的build system,需要替换为另外的一个模式的build system
问题解决:按照File->Workspace Settings->build system路径修改build systemLegacy Build System

pod setup一直没反应

配置完Flutter环境之后,使用flutter doctor检查下环境,会出现以下的提示:

[!] iOS toolchain - develop for iOS devices (Xcode 9.1)
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS.
        For more info, see https://flutter.io/platform-plugins
      To install:
        brew install cocoapods
        pod setup

按照命令安装一波:

brew install cocoapods
pod setup

执行pod setup后,就只有光秃秃的➜ ~ pod setup,其他提示啥也没有……(脑阔疼)

使用flutter doctor看看:

➜  ~ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[] Flutter (Channel stable, v1.9.1+hotfix.4, on Mac OS X 10.14.6 18G103, locale
    zh-Hans-CN)
[] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[!] Xcode - develop for iOS and macOS (Xcode 11.1)
    ✗ CocoaPods installed but not initialized.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin
        code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To initialize CocoaPods, run:
        pod setup
      once to finalize CocoaPods' installation.
[] Android Studio (version 3.5)
[!] IntelliJ IDEA Ultimate Edition (version 2019.2.3)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[] VS Code (version 1.38.1)
[!] Connected device
    ! No devices available

! Doctor found issues in 3 categories.

pod setup没有初始化成功……后来在github找到了相似的问题的解决方案

CocoaPods installed but not initialised #41291

As per solution in #41253:
sudo gem uninstall cocoapods
sudo gem install cocoapods -v 1.7.5
pod setup
sudo gem install cocoapods (if you want latest version)

按照这个方式安装,命令行提示如下:

➜  ~ sudo gem uninstall cocoapods
Successfully uninstalled cocoapods
➜  ~ sudo gem install cocoapods -v 1.7.5
Fetching cocoapods-core-1.7.5.gem
Fetching cocoapods-1.7.5.gem
Successfully installed cocoapods-core-1.7.5
Successfully installed cocoapods-1.7.5
Parsing documentation for cocoapods-core-1.7.5
Installing ri documentation for cocoapods-core-1.7.5
Parsing documentation for cocoapods-1.7.5
Installing ri documentation for cocoapods-1.7.5
Done installing documentation for cocoapods-core, cocoapods after 2 seconds
2 gems installed
➜  ~ pod setup
Setting up CocoaPods master repo
  $ /usr/bin/git clone https://github.com/CocoaPods/Specs.git --progress --
  master
  Cloning into 'master'...
  remote: Enumerating objects: 107, done.
  remote: Counting objects: 100% (107/107), done.
  remote: Compressing objects: 100% (102/102), done.
  remote: Total 3522904 (delta 29), reused 3 (delta 3), pack-reused 3522797
  Receiving objects: 100% (3522904/3522904), 688.96 MiB | 1.53 MiB/s, done.
  Resolving deltas: 100% (2139862/2139862), done.
  Checking out files: 100% (364643/364643), done.

CocoaPods 1.8.3 is available.
To update use: `sudo gem install cocoapods`

For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.8.3

Setup completed

非常完美的解决了pod setup一点反应都没有的问题:

附录

  • 不得不说,Bilibili果然是一个学习的好地方,找到了一堆入门短视频。
  • SwiftUI - Learning:推荐了Swift UI的一些学习资源。

介绍性文章

优秀的资源收集

知识点 说明
ResourceDoc 收集的一些iOS开发的资源,包括官方教程、视频、社区、插件、第三方库、文章等等, 绝大多数是基于Swift,中文资源优先。可惜的是停止更新了,详见:我为什么放弃学习iOS开发

参照的文章

发布了181 篇原创文章 · 获赞 217 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/Notzuonotdied/article/details/102458653