ในปี 2008 Apple ได้ประกาศและเปิดตัว iPhone SDK 2.0 เหตุการณ์นี้เริ่มต้นการปฏิวัติอีกครั้งในการพัฒนาซอฟต์แวร์และเกิดนักพัฒนาสายพันธุ์ใหม่ ตอนนี้พวกเขาได้รับการยอมรับว่าเป็น นักพัฒนา iOS .
นักพัฒนาเหล่านี้หลายคนไม่เคยใช้ Objective-C มาก่อนและนั่นเป็นความท้าทายแรกที่ Apple โยนให้พวกเขา แม้จะไม่คุ้นเคยกับไวยากรณ์และการจัดการหน่วยความจำด้วยตนเอง แต่ก็ประสบความสำเร็จอย่างมากช่วยเติม App Store ด้วยแอพนับหมื่น Apple ปรับปรุง Objective-C อย่างต่อเนื่องในแต่ละรุ่นการเพิ่มบล็อกและตัวอักษรการจัดการหน่วยความจำที่ง่ายขึ้นด้วยการนับอ้างอิงอัตโนมัติและคุณสมบัติอื่น ๆ อีกมากมายที่บ่งบอกถึงภาษาโปรแกรมสมัยใหม่
และหลังจาก 6 ปีที่ปรับปรุงและทำงานกับ Objective-C Apple ก็ตัดสินใจที่จะโยนความท้าทายอีกครั้งให้กับนักพัฒนา อีกครั้งนักพัฒนา iOS จะต้องเรียนรู้ภาษาการเขียนโปรแกรมใหม่: รวดเร็ว . Swift ลบการจัดการตัวชี้ที่ไม่ปลอดภัยและแนะนำคุณสมบัติใหม่ที่มีประสิทธิภาพในขณะที่ยังคงการโต้ตอบกับทั้ง Objective-C และ C
บริษัท รับผิด จำกัด c บริษัท
Swift 1.0 เป็นแพลตฟอร์มการพัฒนาที่มั่นคงและแข็งแกร่งอยู่แล้วซึ่งแน่นอนว่าจะพัฒนาไปในรูปแบบที่น่าสนใจในช่วงหลายปีข้างหน้า เป็นช่วงเวลาที่ดีในการเริ่มต้นสำรวจภาษาใหม่นี้เนื่องจากเห็นได้ชัดว่าเป็นอนาคตของการพัฒนา iOS
จุดประสงค์ของบทช่วยสอนนี้คือการให้ นักพัฒนา Objective-C ภาพรวมโดยย่อของคุณสมบัติภาษา Swift ใหม่ช่วยให้คุณก้าวไปอีกขั้นและเริ่มใช้ Swift ในงานประจำวันของคุณ ฉันจะไม่ใช้เวลามากเกินไปในการอธิบาย Objective-C และฉันจะถือว่าคุณคุ้นเคยกับการพัฒนา iOS
ในการเริ่มต้นสำรวจ Swift สิ่งที่คุณต้องทำก็คือ ดาวน์โหลด XCode จาก App Store และสร้างสนามเด็กเล่นเพื่อทดลอง ตัวอย่างทั้งหมดที่กล่าวถึงในบทความนี้ทำได้ด้วยวิธีนี้
หน้าแรกของ Swift ของ Apple เป็นข้อมูลอ้างอิงที่ดีที่สุดสำหรับการเรียนรู้การเขียนโปรแกรม Swift คุณจะพบว่ามันล้ำค่าและจนกว่าคุณจะเป็น เร่งเต็มที่ด้วยการพัฒนา Swift ฉันเชื่อว่าคุณจะกลับมาที่นี่บ่อยๆ
การประกาศตัวแปรใน Swift ทำได้โดยใช้ var
คำสำคัญ.
var x = 1 var s = 'Hello'
คุณจะสังเกตเห็นว่าสองตัวแปร x
และ s
เป็นประเภทต่างๆ x
เป็นจำนวนเต็มในขณะที่ s
เป็นสตริง Swift เป็นภาษาประเภทที่ปลอดภัยและจะอนุมานประเภทตัวแปรจากค่าที่กำหนด หากคุณต้องการทำให้โค้ดของคุณอ่านง่ายขึ้นคุณสามารถเลือกที่จะใส่คำอธิบายประกอบประเภทของตัวแปรได้:
var y: Int y = 2
ค่าคงที่คล้ายกัน แต่คุณประกาศโดยใช้ let
แทน var
. ไม่จำเป็นต้องทราบค่าของค่าคงที่ในขณะคอมไพล์ แต่คุณต้องกำหนดค่าหนึ่งครั้ง
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time
ตามชื่อของพวกเขาพวกเขาไม่เปลี่ยนรูปดังนั้นรหัสต่อไปนี้จะทำให้เกิดข้อผิดพลาดเวลาคอมไพล์
let c = 1 c = 3 // error
ประเภทอื่น ๆ สามารถประกาศเป็นค่าคงที่ได้ ตัวอย่างเช่นรหัสต่อไปนี้ประกาศว่าอาร์เรย์เป็นค่าคงที่และหากคุณพยายามแก้ไของค์ประกอบใด ๆ คอมไพเลอร์ Swift จะรายงานข้อผิดพลาด:
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error
ค่าคงที่จำเป็นต้องได้รับการเตรียมใช้งานเมื่อประกาศและตัวแปรจะต้องเริ่มต้นก่อนใช้งาน แล้ว Objective-C nil
อยู่ที่ไหน เทียบเท่า? Swift แนะนำ ค่าทางเลือก . ค่าทางเลือกสามารถมีค่าหรือเป็น nil
หากคุณดูรหัสต่อไปนี้คุณจะสังเกตเห็นว่า x
ได้รับมอบหมาย Optional
มูลค่าของ 2014
. ซึ่งหมายความว่าคอมไพเลอร์ Swift ทราบว่า x
อาจเป็น nil
var s = '2014' var x = s.toInt() print(x) // Optional(2014)
หากคุณทำการเปลี่ยนแปลงในรหัสนี้และกำหนดค่า 'abc'
เป็น s
ซึ่งไม่สามารถแปลงเป็นจำนวนเต็มได้คุณจะสังเกตเห็นว่า x
ตอนนี้เป็น nil
.
var s = 'abc' var x = s.toInt() print(x) // nil
ประเภทการส่งคืนของ toInt()
ฟังก์ชันคือ Int?
ซึ่งเป็นไฟล์ Int. ที่เป็นทางเลือก . มาลองเรียกใช้ฟังก์ชันมาตรฐานบน x
:
var x = '2014'.toInt() print(x.successor()) // error
คอมไพเลอร์ส่งสัญญาณข้อผิดพลาดเนื่องจาก x
เป็น เป็นทางเลือกและอาจเป็นศูนย์ . เราต้องทดสอบ x
ก่อนอื่นและตรวจสอบให้แน่ใจว่า successor
ฟังก์ชันถูกเรียกใช้ด้วยจำนวนจริงไม่ใช่ nil
มูลค่า:
var x = '2014'.toInt() if x != nil { print(x!.successor()) // 2015 }
โปรดทราบว่าเราต้องแกะ x
โดยการต่อท้ายเครื่องหมายอัศเจรีย์ (!) . เมื่อเราแน่ใจว่า x
มีค่าเราสามารถเข้าถึงได้ มิฉะนั้นเราจะได้รับข้อผิดพลาดรันไทม์ เราสามารถทำสิ่งที่ Swift เรียกได้ด้วย การผูกเพิ่มเติม การแปลงทางเลือกเป็นตัวแปรที่ไม่ใช่ทางเลือก
let x = '123'.toInt() if let y = x { print(y) }
รหัสใน if
คำสั่งจะดำเนินการต่อเมื่อ x
มีค่าและกำหนดให้ y
โปรดทราบว่าเราไม่จำเป็นต้องแกะ y
ประเภทนี้ไม่ใช่ทางเลือกเนื่องจากเรารู้ x
ไม่ใช่ nil
.
ดูบทช่วยสอน Swift ของ Apple เพื่ออ่านรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกและคุณสมบัติดีๆเช่น โซ่เสริม
ในสตริงการจัดรูปแบบ Objective-C มักจะทำด้วย stringWithFormat:
วิธี:
NSString *user = @'Gabriel'; int days = 3; NSString *s = [NSString stringWithFormat:@'posted by %@ (%d days ago)', user, days];
Swift มีคุณสมบัติที่เรียกว่า การแก้ไขสตริง ทำแบบเดียวกัน แต่กะทัดรัดและอ่านง่ายกว่า:
let user = 'Gabriel' let days = 3 let s = 'posted by (user) (days) ago'
คุณยังสามารถใช้นิพจน์:
let width = 2 let height = 3 let s = 'Area for square with sides (width) and (height) is (width*height)'
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการแก้ไขสตริงของ Swift และคุณสมบัติใหม่อื่น ๆ ให้ไปที่ ที่นี่ .
การประมาณต้นทุนในการจัดการโครงการซอฟต์แวร์
นิยามฟังก์ชันใน Swift แตกต่างจาก C นิยามฟังก์ชันตัวอย่างอยู่ด้านล่าง:
func someFunction(s:String, i: Int) -> Bool { ... // code }
ฟังก์ชัน Swift เป็นประเภทชั้นหนึ่ง . ซึ่งหมายความว่าคุณสามารถกำหนดฟังก์ชันให้กับตัวแปรส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันอื่น ๆ หรือทำให้เป็นประเภทส่งคืน:
func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, '123') // 4 doSomething(f2, '123') // 124
อีกครั้ง Swift อนุมานประเภทของ f1
และ f2
(String
-> Int
) แม้ว่าเราจะสามารถกำหนดได้อย่างชัดเจน:
let f1:String -> Int = stringLength
ฟังก์ชั่นยังสามารถส่งคืนฟังก์ชันอื่น ๆ :
func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))
สามารถดูคำแนะนำเกี่ยวกับฟังก์ชันใน Swift ได้ ที่นี่ .
การแจงนับใน Swift มีประสิทธิภาพมากกว่า Objective-C มาก ในฐานะที่เป็นโครงสร้างของ Swift พวกเขาสามารถมีวิธีการและถูกส่งผ่านด้วยค่า:
enum MobileDevice : String { case iPhone = 'iPhone', Android = 'Android', WP8 = 'Windows Phone8', BB = 'BlackBerry' func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // 'Android'
ต่างจาก Objective-C การแจงนับ Swift สามารถกำหนดสตริงอักขระหรือลอยเป็นค่าสำหรับสมาชิกแต่ละคนนอกเหนือจากจำนวนเต็ม สะดวก toRaw()
วิธีการส่งคืนค่าที่กำหนดให้กับสมาชิกแต่ละคน
การแจงนับสามารถกำหนดพารามิเตอร์ได้:
enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ', ' + city case let .LatLon(lat, lon): return '((lat), (lon))' } } } let loc1 = Location.Address(street: '2070 Fell St', city: 'San Francisco') let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // '2070 Fell St, San Francisco' print(loc2.description()) // '(23.117, 45.988)'
มีข้อมูลเพิ่มเติมเกี่ยวกับการแจงนับ ที่นี่ .
ทูเปิลจัดกลุ่มค่าหลายค่าเป็นค่าผสมเดียว ค่าภายในทูเปิลอาจเป็นประเภทใดก็ได้และไม่จำเป็นต้องเป็นประเภทเดียวกัน
let person = ('Gabriel', 'Kirkpatrick') print(person.0) // Gabriel
คุณยังสามารถตั้งชื่อองค์ประกอบทูเพิลแต่ละรายการ:
let person = (first: 'Gabriel', last: 'Kirkpatrick') print(person.first)
Tuples มีความสะดวกอย่างยิ่งเนื่องจากเป็นประเภทการส่งคืนสำหรับฟังก์ชันที่ต้องการส่งคืนมากกว่าหนึ่งค่า:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3
ไม่เหมือนใน Objective-C Swift รองรับการจับคู่รูปแบบในคำสั่งสวิตช์:
let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println('Number is zero') case (_, 0): println('Number is real') default: println('Number is imaginary') }
ในกรณีที่สองเราไม่สนใจส่วนที่แท้จริงของจำนวนดังนั้นเราจึงใช้ _
จับคู่อะไรก็ได้ คุณยังตรวจสอบเงื่อนไขเพิ่มเติมได้ในแต่ละกรณี เพื่อที่เราจะต้องผูกค่ารูปแบบกับค่าคงที่:
let complex = (2.0, 1.1) switch complex { case (0, 0): println('Number is zero') case (let a, 0) where a > 0: println('Number is real and positive') case (let a, 0) where a <0: println('Number is real and negative') case (0, let b) where b != 0: println('Number has only imaginary part') case let (a, b): println('Number is imaginary with distance (a*a + b*b)') }
สังเกตว่าเราต้องผูกเฉพาะค่าที่เราจะใช้ในการเปรียบเทียบหรือในคำสั่ง case อย่างไร
หากต้องการอ่านเพิ่มเติมเกี่ยวกับสิ่งที่เพิ่มขึ้นไปที่ ที่นี่ .
ไม่เหมือน Objective-C Swift ไม่ต้องการให้คุณสร้างอินเทอร์เฟซและไฟล์การใช้งานแยกต่างหากสำหรับคลาสและโครงสร้างที่กำหนดเอง เมื่อคุณเรียนรู้ Swift คุณจะได้เรียนรู้การกำหนดคลาสหรือโครงสร้างในไฟล์เดียวและอินเทอร์เฟซภายนอกของคลาสหรือโครงสร้างนั้นจะพร้อมใช้งานโดยอัตโนมัติสำหรับโค้ดอื่น ๆ ที่จะใช้
คำจำกัดความของคลาสนั้นง่ายมาก:
class Bottle { var volume: Int = 1000 func description() -> String { return 'This bottle has (volume) ml' } } let b = Bottle() print(b.description())
อย่างที่เห็น, การประกาศและการนำไปใช้งานอยู่ในไฟล์เดียวกัน . Swift ไม่ใช้ไฟล์ส่วนหัวและไฟล์การนำไปใช้งานอีกต่อไป มาเพิ่มป้ายกำกับให้กับตัวอย่างของเรา:
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return 'This bottle of (label) has (volume) ml' } }
คอมไพเลอร์จะบ่นเนื่องจาก label เป็นตัวแปรที่ไม่ใช่ทางเลือกและจะไม่เก็บค่าไว้เมื่อมีการสร้างอินสแตนซ์ Bottle เราจำเป็นต้องเพิ่ม initializer:
class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return 'This bottle of (label) has (volume) ml' } }
หรือเราสามารถใช้ Optional
พิมพ์สำหรับคุณสมบัติที่ไม่ต้องเตรียมใช้งาน ในตัวอย่างต่อไปนี้เราสร้าง volume
อัน Optional Integer
:
class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return 'This bottle of (label) has (volume!) ml' } else { return 'A bootle of (label)' } } }
ภาษา Swift ยังมี structs
แต่มีความยืดหยุ่นมากกว่าใน Objective-C บทแนะนำเกี่ยวกับรหัสต่อไปนี้กำหนด struct
:
struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return '(row)-(letter)' } }
เช่นเดียวกับคลาสใน Swift โครงสร้างสามารถมีวิธีการคุณสมบัติตัวเริ่มต้นและเป็นไปตามโปรโตคอล ความแตกต่างที่สำคัญระหว่างคลาสและโครงสร้างคือ คลาสถูกส่งผ่านโดยการอ้างอิงในขณะที่โครงสร้างถูกส่งผ่านด้วยค่า .
ตัวอย่างนี้แสดงให้เห็นถึงการผ่านคลาสโดยการอ้างอิง:
let b = Bottle() print(b.description()) // 'b' bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // 'b' and 'b2' bottles have 750 ml
หากเราลองใช้กรณีที่คล้ายกันกับ struct
คุณจะสังเกตเห็นว่าตัวแปรถูกส่งผ่านด้วยค่า:
var s1 = Seat(row: 14, letter:'A') var s2 = s1 s1.letter = 'B' print(s1.description()) // 14-B print(s2.description()) // 14-A
เมื่อไหร่ที่เราควรใช้ struct
และเมื่อไหร่ที่เราควรใช้ class
? เช่นเดียวกับใน Objective-C และ C ให้ใช้โครงสร้างเมื่อคุณต้องการจัดกลุ่มค่าสองสามค่าและคาดว่าจะถูกคัดลอกแทนที่จะอ้างอิง ตัวอย่างเช่นจำนวนเชิงซ้อนจุด 2D หรือ 3D หรือสี RGB
อินสแตนซ์ของคลาสเป็นที่รู้จักกันในชื่อวัตถุ อย่างไรก็ตามคลาสและโครงสร้างของ Swift มีความใกล้เคียงในการทำงานมากกว่าในภาษาอื่น ๆ และฟังก์ชันการทำงานมากมายสามารถนำไปใช้กับอินสแตนซ์ของคลาสหรือประเภทโครงสร้างได้ ด้วยเหตุนี้คำทั่วไปที่ใช้ในการอ้างอิง Swift คือ instance
ซึ่งใช้กับสองข้อนี้
เรียนรู้พื้นฐานของคลาสและโครงสร้างของ Swift ที่นี่ .
บัตรเครดิตรั่วไหลด้วยเงิน
ดังที่เราเห็นก่อนหน้านี้คุณสมบัติใน Swift จะประกาศด้วย var
คำสำคัญภายในคลาสหรือนิยามโครงสร้าง นอกจากนี้เรายังสามารถประกาศค่าคงที่ด้วย let
คำให้การ.
struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant
โปรดทราบว่าคุณสมบัติของคลาสนั้นมีการอ้างอิงอย่างชัดเจนเว้นแต่คุณจะนำหน้าด้วย weak
คำสำคัญ. อย่างไรก็ตามมีรายละเอียดปลีกย่อยบางอย่างที่มีคุณสมบัติที่ไม่เป็นทางเลือกที่อ่อนแอดังนั้นโปรดอ่านไฟล์ บทการนับอ้างอิงอัตโนมัติ ในคู่มือ Swift ของ Apple
คุณสมบัติที่คำนวณแล้วไม่ได้เก็บค่าไว้ แต่จะจัดเตรียม getter และ setter ที่เป็นทางเลือกเพื่อดึงและตั้งค่าคุณสมบัติและค่าอื่น ๆ โดยอ้อม
โค้ดต่อไปนี้แสดงตัวอย่างของค่าที่คำนวณ sign
:
enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number <0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }
นอกจากนี้เรายังสามารถกำหนดคุณสมบัติอ่านอย่างเดียวได้โดยใช้ getter:
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }
ใน Objective-C โดยทั่วไปคุณสมบัติจะได้รับการสนับสนุนโดยตัวแปรอินสแตนซ์ซึ่งคอมไพเลอร์ประกาศอย่างชัดเจนหรือโดยอัตโนมัติ ในทางกลับกันใน Swift คุณสมบัติไม่มีตัวแปรอินสแตนซ์ที่เกี่ยวข้อง . นั่นคือไม่สามารถเข้าถึงที่เก็บสำรองของคุณสมบัติได้โดยตรง สมมติว่าเรามีสิ่งนี้ใน Objective-C
// .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @''; } } @end
เนื่องจากคุณสมบัติที่คำนวณใน Swift ไม่มีที่เก็บสำรองเราจึงต้องดำเนินการดังนี้:
class OnlyInitialString { var initial:String = '' var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = '' } } get { return self.initial } } }
คุณสมบัติมีการอธิบายรายละเอียดเพิ่มเติม ที่นี่
มีสิ่งใหม่ ๆ ที่สำคัญอีกมากมายที่จะต้องเรียนรู้ใน Swift เช่น Generics การโต้ตอบกับไลบรารี Objective-C การปิดการผูกมัดทางเลือกและการโอเวอร์โหลดของตัวดำเนินการ บทช่วยสอนเดียวไม่สามารถอธิบายภาษาใหม่ได้อย่างละเอียด แต่ฉันไม่ต้องสงสัยเลยว่าจะมีการเขียนเพิ่มเติมเกี่ยวกับการเรียนรู้การเขียนโปรแกรม Swift แต่เชื่อว่าเรื่องนี้ อ่านด่วน จะช่วยให้นักพัฒนา Objective-C จำนวนมากที่หาเวลาและเรียนรู้รายละเอียดของภาษา Swift ไม่ได้ติดตามและปล่อยให้นก Swift พาพวกเขาไปสู่จุดสูงสุดใหม่