Getting Started
Jump Right In
(这句实在不好翻译)
给CSDN提个建议,把markDown的目录放到左侧更随,在文章顶部太难用了
开发iPhone和ipad,本教程是一个完美的起点,这套课程将作为一个引导教你建立自己的APP,包括工具的最佳使用,语法概念,这将让你的学习路径更平坦。
每节课程都包含一个教程和你需要了解的概念信息,课程是彼此相关联的,你将通过一步步的完成课程中的内容,实现一个真正的APP应用。
当你完成了本课程,你将了解ios应用开发的概念,并且会对swift变成语言有个更深入的了解,而且会发现xcode许多有价值的功能。
About the Lessons(关于教程)
在这个教程里,你将开发一个简单的simple meal tracking app 名字叫FoodTracker。这个app用列表(list)展示美食(meals),并且可以新增或者编辑美食的名称,对美食进行评分,给美食添加图片。
怕你们看不到图片,我还特意把图片重新传了一遍。
第一课是一个playground,playground可以让你交互式的看到程序运行的结果。你可以下载代码并运行(代码我稍后找个国内的git方上去)。
剩下的课程将完成一个xcode的project,这个project会像上面的展示的一样。
Get the Tools(获取开发工具)
你可以冲AppStore获取最新版本的xcode。而且完全是免费的。
提示:
本课程使用xcode 7.0 和 ios sdk 9.0。确保你的版本是正确的
好吧!我们现在开始学习吧。
广告一下:www.vbao100.com,大家多支持啊
Learn the Essentials of Swift (学习要点)
第一个通过playground来学习swift语言,你可以在playground上更改代码,这样有助于迅速理解并掌握swfit语言
提示
因为github访问并不是非常顺利,playground代码我会找一个合适的git放上去,稍后我会提供下载地址,
学习目标
本课程结束时,你需要掌握:
- 常量(constant)和变量(variable)的区别
- 知道何时使用隐式声明或者显式声明
- 理解可选型(optionals)和解包可选型(可能翻译不准确,这个有点类似java的optional)
- 区分解包可选型和不解包可选型(才疏学浅啊,翻译不来,原文:Differentiate between optionals and implicitly unwrapped optionals)
- 了解循环语句和循环条件
- 掌握switch语句
- 掌握where语句
- 区分函数(function)、方法(methods)、初始化(initializers)
- 区分类(class)、结构体(structures)、枚举(enumerations)
- 理解继承(inheritance)和协议(protocol )
- 确定隐式类型和使用Xcode的快速帮助快捷找到更多的信息
- 引入(import)并且使用UIkit
基本类型
常量(constant )声明后不可以更改,而变量(variable )声明后可以更改他的值。
用let声明常量
用var声明变量
var myVariable = 42
myVariable = 50
let myConstant = 42
在swift中,不管是常量还是变量,都是有他的类型(type)的,但是你不需要显示的定义,swift可以自行推断他的类型。像上面的例子中,myVariable是整形(int),myConstant也是整形。
但是,变量一旦声明,是不可以改变他的类型的。
另外,如果你在声明变量时提供的值不能有足够的信息来确定变量的类型,需要显示的声明(我理解是这样的)
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
提示
在xcode中,按住 option 键并且点击变量,可以查看变量的类型
变量永远不会隐式的转换为另外一种类型,如果想要将变量转换为另外一种类型,你必须显示的转换
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
有一种简单的方法可以往字符串中插值,就是在()前面加\,()内写变量
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
可选型(optionals )的声明
let optionalInt: Int? = 9
可选型一旦声明,意味着他一定有值,这个值要么是问号前面的类型,要么是nil值
个人理解
这个应该是swift语言的异常处理机制吧,但是我不用用,写程序时永远在这个上面出错,但是又不知道怎么捕获异常
你必须对他进行解包才能获得optional下面的值,解包使用!
只有使用解包符号(!)才能确定optional不为nil
这种类型在编程过程中使用非常广泛。(所实话,我几乎所有的错误都出在这里)
var myString = "7"
var possibleInt = Int(myString)
print(possibleInt)
上面的代码中,possibleInt = 7 ,因为 myString 里面有个7的整数,但是如果把 myString 改成其他的,不一定能转换成整形,possibleInt可能就是nil
myString = "banana"
possibleInt = Int(myString)
print(possibleInt)
隐式解包可选类型可以像非可选类型值一样使用,并不需要在每次使用时都解包一次。这种用法的前提是隐式解包类型始终是有值的
var implicitlyUnwrappedOptionalInt: Int!
数组(array)是一种有序的数据的集合,使用[]声明,数组的索引从0开始
var ratingList = ["Poor", "Fine", "Good", "Excellent"]
ratingList[1] = "OK"
ratingList
创建一个空数组的语法
// Creates an empty array.
let emptyArray = [String]()
注释的声明可以有两种方式
使用 //
使用 /* */
没有写完,改天继续翻译,翻译起来比学的还慢~~~~
我兄弟的网站,大家捧捧场:唯宝网–赴美生子社区,www.vbao100.com
optional一旦声明,一定是有一个默认值的,这个默认值可能是nil,使用的时候可以对optional进行解包。(这个是我自己的理解:原文:An implicitly unwrapped optional is an optional that can also be used like a nonoptional value, without the need to unwrap the optional value each time it’s accessed. This is because an implicitly unwrapped optional is assumed to always have a value after that value is initially set, although the value can change. Implicitly unwrapped optional types are indicated with an exclamation mark (!) instead of a question mark (?).)
var implicitlyUnwrappedOptionalInt: Int!
你很少需要在您自己的代码创建隐式打开optional。
流程控制语句
swift中有两种流程控制语句,一种是条件控制语句,如if何switch,
一种是循环控制语句,比如 for-in 和 while。
if语句的示例:
let number = 23
if number < 10 {
print("The number is small")
} else if number > 100 {
print("The number is pretty big")
} else {
print("The number is between 10 and 100")
}
if语句可以用来检查optional类型的变量是否有值
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
上面的例子中,如果optionalName为nil值,那么在if语句中optionalName不会被解包,name也不会被赋值,if的条件是false。
if 语句后面可以跟多个条件,如果要让if语句的内容被执行,那么他的条件必须都为true才可以,比如:
var optionalHello: String? = "Hello"
if let hello = optionalHello where hello.hasPrefix("H"), let name = optionalName {
greeting = "\(hello), \(name)"
}
switch语句在swift中是非常强大的,他在swift中支持各种类型的数据比较操作,比局限于数字或字符串。
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
default:
let vegetableComment = "Everything tastes good in soup."
}
注意上面代码中常量(let vegetableComment)何时被定义,这个有点像if语句的条件,where比用来进一步约束条件,当条件成立时,let vegetableComment才会被定义。
在swift语言中,swtich语句会在执行完case后直接跳出循环,所以你不必再每个case后添加跳出循环的语句。
switch必须能够覆盖全部的情况,所以默认情况下要有default语句,但是在switch的条件是枚举类型时(enumeration),你可以做到用case覆盖全部的情况,可以不用设置default。
var firstForLoop = 0
for i in 0..<4 {
firstForLoop += i
}
print(firstForLoop)
上面的例子中使用了半开操作符( ..<),半开操作符不包含该该数值,所以他的循环是冲0到3,如果你用封闭操作符(…),他会包含这个数值,比如
var secondForLoop = 0
for _ in 0...4 {
secondForLoop += 1
}
print(secondForLoop)
_ 是一个通配符
函数和方法
function 一个可重用的代码段。
使用func定义一个方法,方法可以包含0个到多个参数,参数的定义方法是name: Type,函数的返回值是可选的,如果有返回值,要用(->)定义返回值类型。
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
调用函数(第一个参数不用写他的名字)
greet("Anna", day: "Tuesday")
greet("Bob", day: "Friday")
greet("Charlie", day: "a nice day")
方法(methods)是一种特殊的函数,方法的调用可以使用点操作符。
类和初始化
在面向对象的编程过程中,程序的行为主要是在对象之间进行交互的。
object 是class的一个实例,class是object的设计蓝图。
class存储有关自己的附加信息的属性,并使用方法定义自己的行为。
类的定义使用关键字class,属性定义和定义变量一样,方法定义和函数定义一样。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
创建一个类的实例对象,使用点符号调用类的属性或方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
初始化initializer是一个方法method,该方法method为类class实例的使用做一些准备工作
class NamedShape {
var numberOfSides = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class 中的属性在实例化时必须是有值得,不管是在属性定义时还是在初始化时。
初始化方法不可以用init来调用,但可以通过实例化的时候调用他。
let namedShape = NamedShape(name: "my named shape")
子类可以继承父类的属性,子类也可以继承父类的方法,并对方法进行重写(使用 override 关键字)
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let testSquare = Square(sideLength: 5.2, name: "my test square")
testSquare.area()
testSquare.simpleDescription()
有时,对象的初始化可能会出错,比如,参数提供的值超出范围,或者参数缺失,这叫做failable初始化,他会返回一个nil值,
class Circle: NamedShape {
var radius: Double
init?(radius: Double, name: String) {
self.radius = radius
super.init(name: name)
numberOfSides = 1
if radius <= 0 {
return nil
}
}
override func simpleDescription() -> String {
return "A circle with a radius of \(radius)."
}
}
let successfulCircle = Circle(radius: 4.2, name: "successful circle")
let failedCircle = Circle(radius: -7, name: "failed circle")
枚举和结构体
枚举(Enumerations)和结构体(structures)有类差不多的功能。
enumerations 是一组相关的值。
enumerations 可以有自己的方法。
创建enumeration的方法是使用关键字enum
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue
在上面的例子中,枚举的原始值类型为int,所以你必须指定第一个原始值。原始值的其余部分分配秩序。您还可以使用字符串或浮点数为原始类型枚举。使用rawValue属性来访问枚举成员的原始值。
使用init ?( rawValue :)初始化
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}
结构体和类非常相似,他们最主要的区别是,在代码中传值时,结构体是复制,而类是引用。
用struct创建结构体
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
协议(Protocols)
协议适合用来设计一个功能的蓝图,包括方法和属性。协议实际上不会提供任何功能设计,只是描述一个功能的样子。协议可以随后通过类或者枚举、结构体来提供代码逻辑,满足协议要求的任何类型被认为符合该协议。
用protocol来定义协议
protocol ExampleProtocol {
var simpleDescription: String { get }
func adjust()
}
提示
在simpleDescription后的{ get }属性表明它是只读的,这意味着该属性的值可以查看,但不可以改变。
类、枚举、结构体要采用协议,使用:后面跟协议的名字,如果要采用多个协议,就用逗号分隔,如果这个类有父类,那么父类必须写在:后的第一个位置。
这里, SimpleClass采用ExampleProtocol协议,并通过实施simpleDescription属性和adjust()方法符合协议。
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
swift 和 cocoa touch
现在,你已经掌握了swift的标准库,但是在开发是,可能会用到很多超出标准库的东西,最多的可能是UIKit。
引入UIKit
import UIKit
感谢唯宝网朋友的支持,我很多都是问他们的,呵呵。
大家多支持下他们的网站,www.vbao100.com
Building The UI
Build a Basic UI
这一课主要是熟悉xcode工具,通过这节课,你将建立一个简单的UI,他应该像下面这个样子:
学习目标
- xcode中创建项目
- 知道xcode创建工程文件后的关键内容
- 打开或者切换文件或者工程
- 通过模拟器运行app
- 增加、修改、删除storyboard上的UI元素
- 通过 Attributes inspector 调整UI的属性
- 查看和使用outline view重新排列UI元素
- 用Preview assistant editor预览UI
- 制定出能自动适应使用自动布局在用户的设备尺寸的UI
创建一个新工程
Xcode中包括一些内置的开发常见类型的iOS应用程序,如游戏,基于选项卡的导航应用,以及应用模板表视图为基础的应用程序。大多数的这些模板已经预先配置接口和源代码文件。单查看应用程序:在这一课中,你将与最基础的模板开始。
创建新工程
1、打开xcode
如果出现的不是欢迎窗口项目窗口,不用担心,你可能创建或在Xcode中打开了一个项目之前。只要使用菜单项在下一步创建项目。
2、在欢迎界面,点击“Create a new Xcode project”(或者File > New > Project)
xcode打开一个新窗口让你选择模板。
3、在iOS中选择application,
4、在主界面,选择 Single View Application并点击next
5、在出现的对话框中,使用下列值命名您的应用程序,并为项目选择附加选项:
- Product Name: FoodTracker
Xcode使用你输入名字命名您的项目和应用程序的产品名称。
Organization Name: 您的组织或你自己的名字。留空
- Organization Identifier: 你的组织标识符
- Bundle Identifier: 这个值是根据您的产品名称和组织标识符自动生成。
- Language: Swift
- Devices: Universal ,一种通用的应用程序可以在iPhone和iPad上运行。
- Use Core Data: Unselected.
- Include Unit Tests: Selected.
- Include UI Tests: Unselected.
6、点击next
7、出现一个新的对话框,选择保存地址,xcode会在workspace window自动打开你的新工程。
熟悉xcode
运行模拟器
1、在 Scheme pop-up menu选择iphone6
2、点击Run button
也可以选择 Product > Run (或用快捷键 Command-R).
查看源代码
AppDelegate.swift
1、确保 project navigator 打开的是 navigator area.
在Project Navigator显示项目中的所有文件。如果project navigator没有打开,点击navigator selector bar最左边的按钮。 (或者,选择iew > Navigators > Show Project Navigator)
2、如果需要的话,按一下旁边的三角形来打开它在Project Navigator的FoodTracker文件夹。
3、选择 AppDelegate.swift
AppDelegate.swift有两个主要的函数
- 它创建的进入点,让你的应用程序运行和循环,提供输入事件到您的应用程序。这项工作是交由UIApplicationMain属性( @UIApplicationMain )。 UIApplicationMain创建应用程序对象,该对象是负责管理该应用的生命周期和应用程式委托对象。
- 它定义一个AppDelegate类,这个类是用来规划应用程序的委托对象。
该AppDelegate类包含一个属性:window。与此属性在应用程序所有的窗口上都会被委托跟踪。窗口属性是optional,这意味着它可以在某一点上具有任何nil值。
var window: UIWindow?
该AppDelegate类也包含重要方法的模板实现。这些预定义的方法允许应用程序对象和应用程序委托通讯。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
func applicationWillResignActive(application: UIApplication)
func applicationDidEnterBackground(application: UIApplication)
func applicationWillEnterForeground(application: UIApplication)
func applicationDidBecomeActive(application: UIApplication)
func applicationWillTerminate(application: UIApplication)
在应用程序状态转换,例如,应用程序启动,过渡到背景,应用终止,应用程序对象冲委托调用相应的方法,让它一个作出适当的反应。你不需要做任何特殊的事情以确保这些方法在正确的时候被调用,应用程序对象帮你处理了那部分工作。
每一种自动实现的方法有一个默认的行为。如果模板实现空或从AppDelegate类中删除这些方法,那么应用程序只会调用该方法的默认行为。给这些方法模板添加自定义代码,它会在被调用的时候执行。
在这一课中,你将不会被使用的自定义应用程序委托代码,所以你没有做对AppDelegate.swift文件进行任何更改。
View Controller 源文件
每一个视图模板有一个源文件:ViewController.swift ,从project navigator选择他查看文件。
这个文件定义了一个UIViewController的子类,并命名为ViewController。这个类继承了UIViewController的行为。要扩展或者重写这些方法,你可以用override重写UIViewController
里面的方法。
在这一科中,你不需要重写didReceiveMemoryWarning方法,所以可以直接删掉。
现在,你的代码应该看起来是这样的:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
打开storyboard
storyboard是应用程序的用户界面的可视化表示,显示内容和屏幕之间的通讯。您可以使用storyboard制作应用程序流程。
打开你的storyboard
- 在project navigator中选择main.storyboard
你的storyboard应该看起来像这样:
现在,你的storyboard中只包含了一个场景(scene),场景左边的箭头是进入点,他表示这个场景将在app启动后第一个被载入。
当你在iPhone6模拟器上跑你的app时,在这个场景中的东西就是你在设备屏幕上看到的东西。但是,当你看到画布(canvas)上的场景时,你会发现它不具备iPhone6屏幕的确切尺寸。这是应为场景只是一个通用表达,他可以适用于任何设备和任何方向。你可以定义自适应的用户界面,让他在任何设备和任何方向都有良好的表现。
建立基本的UI
xcode提供一个对象库,你可以把里面的添加到storyboard中。其中一些元素会直接呈现在UI上,比如label,text field,但是有一些元素不会呈现在UI上,比如手势识别,和视图控制器(view controllers)。
出现在UI的元素被称作views。views把内容呈现给用户。他们是你构建UI的基础。他们有各种内置的行为,包括显示自己和反应用户输入。
所有的view对象都是UIView类或者他的子类。
通过添加一个文本框(UITextField类)的UIView这样一个子类到场景。他是一个文本字段,可在单行输入文本作为一餐的名称。
添加一个text field到你的用户界面
- 打开Object library
- 找到或者使用filter field找到text field
- 拖动他到你的场景中
- 拖动text field 到合适的大小
配置text field
- 在text field 被选中的情况下,打开Attributes inspector
- 找到Placeholder并输入Enter meal name
配置text field的键盘
- 在text field 被选中的情况下,打开Attributes inspector
- 找到Return Key的标签并且选择select Done(这一变化将使得键盘上的默认回车键改变成一个完成的关键。)
- 找到Auto-enable Return Key并选中(这一变动确保用户就不会进入一个空字符串作为一餐的名称。)
添加一个label到你的场景
label不是交互式的;它只是显示在UI的静态文本。为了帮助您了解如何在UI元素之间的交互定义,您将配置这个标签来显示用户输入到文本字段中的文本。这将是测试文本字段走的是用户输入,并正确处理它的好方法。
在Object library中找到label并把他拖入到场景中,改变他的大小,双击并且输入 Meal Name。
添加一个button到场景
在object library中找到button,并把他拖入到场景,双击改变他的文字为Set Default Label Text.
查看outline view
outline view让你看到你的storyboard中的对象的分层表示。你应该能够看到text field,label和button。
views不仅在屏幕上显示自己和响应用户的输入,可作为其他视图的容器。
视图有不同的层级,内部的为子视图。
预览用户界面
打开 assistant editor.选择 Automatic to Preview > Main.storyboard (Preview).
你可以不用模拟器看到界面效果
这个UI和我们设想的不一样,因为他并不适应当前的用户界面尺寸。
采用auto layout
关闭预览界面,只打开storyboard。
- 按住 Shift 键,选择 text field, label, 和 button.
- 在编辑器右下角,选择stack(xcode会给选中的元素打个包,放在一个stack中,并且xcode会自动识别这些元素应该是水平分布还是垂直分布)
- 在Attributes inspector中找到Spacing field并且输入12
- 选中Pin按钮,调整设置
未完,待续。。。。