Showing posts with label Swift cơ bản. Show all posts
Showing posts with label Swift cơ bản. Show all posts

Monday, September 11, 2017

Bài 6 - Biến toàn cục, biến địa phương

Đây cũng là một khái niệm bạn cần chú ý khi mới học.
Một biến được khai báo sẽ có giá trị trong cái ngoặc mở và đóng chứa biến đó.
Tại Playground, copy vào các dòng sau
let so=10
func f(){
     print("Giá trị của so là:"+String(so))
}
 f()
Chương trình sẽ  in ra số 10.

Bây giờ thêm dòng sau vào trong hàm f().
var so=8

Bây giờ chạy chương trình màn hình lại in ra số 8, biến so ở trong phương thức f() và ở ngoài là khác nhau, biến ngoài gọi là biến toàn cục, bên trong gọi là biến địa phương.
Một biến khai báo ngay sau dấu mở của Class sẽ là biến toàn cục, khi bạn dùng nó Xcode sẽ tô màu xanh. Các biến địa phương có màu đen.
Thêm dòng sau xuống dưới cùng
let b=so+5

Màn hình in ra 15 là tổng của số 10 với 5, chữ so có màu xanh. Như vậy, biến địa phương so=8 chỉ có giá trị trong cái ngoặc giới hạn của nó, ở đây là hàm f().
Bây giờ hãy rào dòng let so=10 thành comment.

Xcode báo lỗi chưa khai báo của so, vì so=8 ở trên chỉ dùng được trong phạm vi hàm f() mà thôi. Nó có màu đen tức là biến địa phương.
Bây giờ bỏ rào đi, thêm chữ b xuống dưới cùng, cả so và b sẽ có màu xanh, nó trở thành biến toàn cục và lỗi cũng hết.

Khi mới học bạn không nên đặt tên biến địa phương trùng với biến toàn cục vì có thể nhầm. Lúc sau quên mất mình đang tính toán với giá trị nào.

Các ngoặc trong Swift phân chia phạm vi của các biến, nếu không để ý, mỗi khi khai báo biến mới, cứ thấy nó màu xanh là bạn biết đó là biến toàn cục, đen là địa phương, vậy sẽ không bị nhầm.

Sunday, September 10, 2017

Bài 5 - Try catch, chuyển kiểu

Giả sử bạn có chuỗi “8”, bạn muốn chuyển nó thành số 8. Bạn sẽ làm như sau
let a="8"
let number = NSNumberFormatter().numberFromString(a)
var so = number!.integerValue
let b=9+so

Lúc này biến so được tạo ra là một số nguyên với giá trị 8, nên bạn có thể cộng nó với 9 thành 17 như ở dòng cuối.
Hãy sửa chữ “8” thành “8m”, chương trình sẽ báo lỗi ở dòng 
var so = number!.integerValue vì lúc này không chuyển được “8m” thành số nên bị lỗi, chương trình bị dừng.

Ta sẽ cho lệnh Try catch vào để ngăn chương trình bị dừng.
do {
let number = try NSNumberFormatter().numberFromString(a)
var so = number!.integerValue
let b=9+so
}
Catch let error as NSError{
print("Lỗi chuyển kiểu")
}
Chương trình vẫn bị lỗi, trong khi lẽ ra nó phải in ra bên phải dòng chữ báo lỗi chứ không phải là hiện dấu đỏ báo interrupted, tức bị dừng không chạy.

Để bắt được lỗi, ta phải dùng lệnh if như sau:
iflet number = NSNumberFormatter().numberFromString(a){
var so = number.integerValue
let b=9+so
}
else{
print("Lỗi chuyển kiểu")
}
Kết quả màn hình đã in ra dòng lỗi, chương trình không bị dừng.

Bỏ chữ m trong biến a đi, mọi thứ lại bình thường, kết quả ra 17 đúng như lệnh if.
Tại sao dùng try catch mà không bắt được lỗi, đó là vì nó không support cho trường hợp này, nhưng trong khi lập trình ta vẫn có khi phải dùng nó.
Lệnh try catch giới thiệu ở đây để bạn biết, sau này thấy nó coi như bạn cũng đã biết rồi. 

Bài 4 - Đối tượng

Copy đoạn code sau cho vào trong Playground
func show(){
print("Đây là dòng chữ ví dụ")
}
show()
class vidu{
func tinhnhan(a:Int, b:Int)->Int{
let c=a*b
return c
}
}

Ta thấy màn hình chỉ chạy ra dòng chữ "Đây là dòng chữ ví dụ"
Đó là vì phương thức tinhnhan hiện giờ đang nằm trong class vidu, chưa dùng nó nên chưa có gì.
Thêm các dòng sau vào
var tinh =  vidu();
let so=10;
let so2=12;
tinh.tinhnhan(so,b:so2)

Việc ta vừa làm chính là tạo đối tượng và sử dụng nó.
Dòng var tinh =  vidu() tạo ra đối tượng tinh của lớp vidu
Bên dưới ta dùng đối tượng kèm dấu chấm để gắn vào phương thức của lớp gốc là dùng được.
Vậy bạnchỉ cần biết cả dòng đó tạo ra đối tượng để ta dùng các phương thức nằm ở một lớp khác.
Khi bạn làm ứng dụng, nó có thể rất dài, có nhiều class, có phương thức phải dùng trong nhiều class. Bạn không cần copy nó đi mọi chỗ mà cứ để đó, chỉ cần dùng dòng code mẫu tạo ra một đối tượng với tên tùy chọn. Rồi gắn đối tượng đó với phương thức trong lớp qua dấu chấm là dùng được phương thức đó.
Hãy tạo một class có tên vidu2, trong đó có phương thức tinhcong
class vidu2{
func tinhcong(a:Int,_ b:Int)->String {
let c=a+b
return"Kết quả là " + String(c)
    }

}
var doituong =  vidu2();
doituong.tinhcong(so,so)

Ta thấy đối tượng là cách để ta sử dụng class, muốn dùng phương thức trong một class nào đó thì ta tạo ra đối tượng để dùng.
Hãy tự thêm các phương thức khác vào class để thực hành.Sửa tên đối tượng đi, chỗ doituong thay bằng cái gì khác, chạy thử, đó gọi là đang truy xuất vào phương thức trong một lớp khác.
Đến đây bạn cũng đã rõ lớp là gì, việc chúng ta tạo các class như vidu, vidu2 chính là các lớp. Nói đơn giản thì lớp là các dòng lệnh nằm trong một cấu trúc mở đầu bằng class Tên lớp{ và kết thúc bằng cái ngoặc đóng }
Định nghĩa này nó hơi buồn cười, vậy hãy thử đọc cái bài bản xem:
“Lớp là một khái niệm dùng để biểu diễn một tập các đối tượng, lớp có phương thức và thuộc tính”.
Nghe có vẻ hàn lâm hơn nhưng khi mới học, bạn có đọc hàng trăm lần cũng chả ích gì. Bạn cứ code đi, tự mình tạo một class mới với các phương thức bên trong. Làm được rồi đọc lại cái định nghĩa hàn lâm bạn sẽ hiểu nó dễ dàng.
Khi đã quen, hiểu được phương thức, đối tượng là bạn đã có thể bắt tay vào làm cái gì đó rồi.
Liệu bạn có thấy nó đơn giản quá, ai cũng học được ?

Chỉ từ những thành phần cơ bản như thế, người ta có thể làm ra được nhiều thứ rất khó tin. Cũng như dùng một cái que và một sợi dây để xoi gỗ ra lửa vậy. Trông thì rất đơn giản đấy, nhưng liệu bạn có làm được hay không ?

Bài 3 - Phương thức

Copy đoạn lệnh sau vào trong Playground
func show(){
print("Đây là dòng chữ ví dụ")
}
Bên phải màn hình trắng trơn không có gì

Gõ thêm dòng show() vào chạy thử.

Bây giờ màn hình đã in ra dòng chữ ta muốn.
Tiếp theo ở trên dấu ngoặc dưới cùng, copy đoạn code sau vào
func tinhnhan(a:Int,_ b:Int){
let c=a*b
print("Kết quả nhân hai số là: "+String(c))
}
Bên dưới thêm các dòng sau:
let so=10;
let so2=12;
tinhnhan(so,so2)
Màn hình có kết quả 120 được tính ra.

Các đoạn code có tên show(), tinhnhan() được gọi là hàm hay phương thức.
Vậy phương thức là tập hợp các dòng lệnh bắt đầu bằng biểu thức kiểu như func tên gọi{
Kết thức bằng dấu }
Phương thức sẽ làm một cái gì đó, như với show() là để in ra màn hình dòng chữ, với tinhnhan() là để tính tích hai số bất kỳ.
Ban đầu ta không cho dòng show() vào thì nó không hiện ra gì cả, đó là vì ta chưa gọi phương thức.
Bắt đầu từ funcshow() là ta khai báo phương thức, ở dưới gọi để dùng nó, không dùng thì coi như không có gì.
Bạn có thể thắc mắc sao không để lệnh print("Đây là dòng chữ ví dụ")luôn, còn cần show() làm gì, đương nhiên đây là ví dụ đơn giản. Khi làm thực tế, các phương thức có thể rất dài, cần dùng nhiều lần. Bạn sẽ khai báo nó một lần, lúc nào dùng lại gọi.
Như với tinhnhan(), mỗi khi cần nhân 2 số a, b bất kỳ bạn chỉ dùng một dòng tinhnhan(a,b) chứ không cần gõ lại lệnh nhân cụ thể nữa. Đó chính là lợi ích của dùng phương thức.
So sánh show() và tinhnhan() ta thấy show không có gì trong ngoặc, ta gọi là nó không nhận đối số truyền vào, còn tinhnhan nhận vào 2 biến số nguyên a, b.
Thử xoá dấu gạch trước chữ b trong tinhnhan()

Xcode báo lỗi và buộc bạn thêm chữ b: vào trước so2
Đây là cái bất tiện của Swift, để gõ luôn các đối số tiếp theo trong phương thức, ta phải thêm dấu gạch chân trước nó khi khai báo.
Tiếp theo, copy dòng code sau xuống dưới phương thức tinhnhan()
func tinhnhan2(a:Int, b:Int)->Int {
let c=a*b
return c
}
let so3=15;
let so4=2;
let d=tinhnhan2(so3,so4)
print("Kết quả phương thức hai là: "+String(d))Bên trên thêm Màn hình hiện ra dòng kết quả.

Bây giờ hãy so sánh tinhnhan() và tinhnhan2(), ta thấy chỗ mũi tên và chữ int ở phần đầu tinhnhan2() là khác tinhnhan().
Nếu không có mũi tên ta gọi là phương thức không trả lại giá trị, có mũi tên tức nó trả lại giá trị nào đó, int tức trả lại một số nguyên. Nên trong tinhnhan2 phía cuối có dòng return c.
Nếu phương thức khai báo không có mũi tên, không có chữ return.
Vì tinhnhan2 chỉ trả lại giá trị nhân nên khi dùng nó ở trên, muốn có thêm dòng chữ kết quả ta cần thêm lệnh print vào.
Phương thức có thể trả lại giá trị là một chuỗi, copy thêm dòng code sau vào dưới tinhnhan2.
func tinhcong(a:Int,_ b:Int)->String {
let c=a+b
return"Kết quả là " + String(c)
}
tinhcong(so3,so4)
Chạy thử ra kết quả như sau.
Vì tinhcong cho ra kết quả là một chuỗi nên khi dùng ta không cần thêm lệnh in nữa.
Phương thức cũng có thể trả lại mảng, copy đoạn code sau xuống dưới phương thức tinhcong()
func tinhtoan(a:Int,_ b:Int)->[Int] {
var ar=[Int](count: 3, repeatedValue: 0)
let c=a+b;
let d=a-b;
let e=a*b;
    ar[0]=c;
    ar[1]=d;
    ar[2]=e;
return ar
}
var kq=[Int](count: 3, repeatedValue: 0)
kq=tinhtoan(so3,so4)
Kết quả ta có mảng 3 số nguyên của các phép tính cộng, trừ, nhân hai số đầu vào.

Bài tập
Làm phương thức chia 2 số, trả lại kết quả kiểu Double

Phương thức tính căn, làm tròn kết quả còn hai chữ số sau dấu phảy, dùng công thức let n=sqrt(Double) để tính căn một số

Bài 2 - Mảng, chuỗi

Mảng là tập hợp nhiều giá trị có cùng kiểu dữ liệu
Đây là mảng số
let data = [1, 2,3, 4,5]
Mảng các chữ.
let data2 = ["Thứ hai","Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy", "Chủ nhật" ]mảng các chữ
var mang = [String](count: 12, repeatedValue: " ")
var mang2 = [Int](count: 12, repeatedValue: 0)

Ta khai báo mảng kèm luôn số phần tử, các dữ liệu đại diện, 0 tức là mảng số, dấu cách trắng là mảng chuỗi.
Để cho phần từ vaò mảng, ta dùng lệnh append
mang.append("Thứ hai");
mang2.append(9);
Để lấy kích thước mảng
let kichthuoc=data.count
Gõ lệnh for để tính tổng các giá trị lẻ trong mảng data
for i in0..<5 {
if(data[i]%2==1){
tong=tong+data[i]
    }
}

Kết qua chạy ra là 9, hãy so sánh với bài 1, cũng là từ 0 đến 4 mà bài 1 ra kết quả tổng lẻ có 4 là sao?
Đó là vì ở bài 1 ta cộng các số lẻ từ 0 đến 4 thì chỉ có 1 và 3. Còn đây ta cộng các vị trí trong mảng, với i=0 là vị trí đầu, giá trị 1, i=4 là vị trí 5, giá trị 5.
Vậy hãy cẩn thận với chỉ số mảng, i luôn nhỏ hơn kích thước mảng 1 đơn vị. Mảng có 10 phần tử, i lớn nhất là 9. Vòng lặp for với mảng rất hay bị nhầm kích thước mảng,cần chú ý.
Nếu bạn sửa chỗ %2==1 thành %2==0, nó sẽ in ra tổng các số chẵn, kết quả là 6
Dòng tong=tong+data[i]; có nghĩa là ta cộng dồn các giá trị tong, các giá trị sau được cộng luôn vào giá trị trước. Giả sử sau lần chạy đầu tiên, i=0 ta được giá trị 1, tiếp theo được giá trị 3, thì nó sẽ cộng luôn vào 1 thành 4, cứ như vậy đến cuối cùng ta có tổng của toàn bộ các số thỏa mãn yêu cầu của lệnh if.
Dòng tong=tong +data[i] hay được viết như sau tong+=data[i];
Cách viết này rất phổ biến nhưng nhìn hơi khó hiểu, bạn cứ nên viết rõ ra có 2 chữ tong hai bên sẽ dễ nhìn hơn.
Hãy thêm vào mảng data các số 35,88
Nếu muốn biết vị trí của số 35 trong mảng data, ta dùng lệnh for duyệt tất cả các phần tử
for i in0..<data.count {
if(data[i]==35){
vitri=i+1
    }
}
Giá trị in ra sẽ là 6, cộng thêm 1 vào i vì trong mảng, i=0 là số thứ nhất.

Giả sử ta muốn đếm xem có bao nhiêu số chia hết cho 5 trong mảng data.
var dem=0
for i in0..<data.count {
if(data[i]%5==0){
dem=dem+1
    }
}
Khi chạy for, cứ mỗi khi có một phần tử chia hết cho 5 thì biến dem lại tăng lên 1 đơn vị, kết quả ra 2.

Ta thử tìm số lớn nhất trong mảng này, copy đoạn code sau vào
var max=data[0]
for i in0..<data.count {
if(data[i]>max){
max=data[i]
    }
}

Hãy xem lệnh for, ban đầu ta khai báo biến max và gán luôn giá trị là phần tử đầu tiên của mảng. Sau đó chạy for để so sánh từng giá trị của mảng với max, nếu có giá trị lớn hơn, gán giá trị đó cho max.
Với mảng 2 chiều, ta khai báo nó như sau
let mang3  = [[1, 2, 3, 4, 5],[1, 2, 3, 4, 5],[1, 2, 3, 4, 5],[1, 2, 3, 4, 5] ]
Đó là mảng có 3 dòng, mỗi dòng có 5 phần tử, phần tử ở dòng đầu tiên, cột thứ 3 sẽ được viết là mang3[0][2], đó là số 3
Hoặc ta chỉ khai báo số dòng, cột, kiểu giá trị của mảng
var mang4 = Array(count: 2, repeatedValue:Array(count:3,repeatedValue: " "))

Đó là mảng có 2 dòng, mỗi dòng có 3 phần tử, ta thêm các giá trị vào
mang4[0][0]=4;
mang4[0][1]=8;
mang4[0][2]=6;
mang4[1][0]=5;
mang4[1][1]=9;
mang4[1][2]=3;
Lúc này các phần tử mảng trông sẽ như sau
4 8 6
5 9 3
Phần tử ở dòng đầu tiên, cột thứ 3 sẽ được viết là mang4[0][2], đó là số 6.
Để tính tổng các phần tử trong mang4, ta dùng vòng lặp for kép
var tong2=0
for i in0..<2 {
for j in0..<3 {
tong2=tong2+mang4[i][j]
}
}
Kết quả ra 35

Vòng for kép không dễ hiểu, hãy nghĩ như sau:
Đầu tiên cho i=0, chạy for đơn bên dưới với j từ 0 đến 2 để cộng dòng 1
Tiếp theo cho i=1, chạy for đơn bên dưới với j từ 0 đến 2 để cộng dòng 2
Vậy nó là 2 lần, hoăc tổng quát là i lần chạy for đơn. Ở đây i biểu thị số dòng, với i=0 nó cộng dòng 1, i=1 nó cộng dòng 2 của mảng.
Bạn luôn nên đặt i ở ngoài, j ở trong để dễ hình dung khi khi gán i, j để hiểu nó.
For kép chỉ dùng được khi bạn đã dùng quen for đơn, bạn hiểu lặp lại for đơn chính là for kép, khi đó tự bạn biết khi nào buộc phải dùng nó.
Mảng 2 chiều hơi khó hình dung, dễ lẫn dòng, cột. Nhưng nó tiện để gán dữ liệu vào. Khi làm ứng dụng, có những lúc bạn chỉ có thể dùng mảng 2 chiều vì mảng 1 chiều là không đủ. Lúc đó tự bạn sẽ hình dung trong đầu ra cách để dùng nó. Vậy ban đầu, cứ hiểu về mảng 1 chiều là được rồi.
Ta sẽ xem thêm về chuỗi, tức các ký tự String
Đối với chuỗi, lệnh cần biết nhất là chặt chuỗi, tức chia nhỏ ký tự ra
Giả sử ta có chuỗi.
let chuoi="Đay la vi du, phan chia chuoi, theo dau phay";
Ta có thể tạo một mảng bằng cách chặt chuỗi như sau
let mang5 = a.componentsSeparatedByString(",")
Lúc này mang5 tạo thành có 3 phần tử “Đay la vi du”, “ phan chia chuoi”,” theo dau phay”
Để bỏ dấu cách trắng đầu chữ “ phan chia chuoi”, ta dùng lệnh
let bocach=mang5[1].characters.dropFirst()
let chuoi2=String(bocach)
Lúc đó kết quả là “phan chia chuoi” đã mất dấu cách ở đầu

Để đếm số ký tự của chuỗi, ta dùng lệnh characters.count

Chú ý ký tự trắng cũng được tính là một ký tự.
Dùng chuỗi để cắt thành mảng rất hay dùng trong thực tế lập trình.
Bài tập
Tạo một mảng các số bất kỳ, in ra tổng các số chia hết cho 3, 6, 9
Đếm xem có bao nhiêu số chia hết cho 8.
Tìm xem số 30 ở vị trí nào, nếu trong mảng không có số 30 thì sao.
In ra giá trị nhỏ nhất của mảng.
Can năm gồm có Giáp, Ất, Bính, Đinh, Mậu, Kỷ Canh, Tân, Nhâm, Quý.
12 địa chi gồm Tý, Sửu, Dần, Mão, Thìn, Tỵ, Ngọ, Mùi, Thân, Dậu, Tuất, Hợi
Lấy năm dương chia cho 10, số dư đổi thành can. Dư 1 là Tân, 2 Nhâm, 3 Quý, 4 Giáp, 5 Ất, 6 Bính, 7 Đinh, 8 Mậu, 9 Kỷ, 0 Canh.
Lấy năm dương chia cho 12, số dư đổi thành chi. Dư 1 là Dậu, 2 Tuất, 3 Hợi, 4 Tý, 5 Sửu, 6 Dần, 7 Mão, 8 Thìn, 9 Tỵ, 10 Ngọ, 11 Mùi, 0 Thân.
Tính để biết năm âm lịch từ năm dương.

Tôi làm giúp bạn phần đổi ra can, bạn tự làm nốt phần đổi ra chi.