11/11/2022

Swift: Sinh chuỗi ngẫu nhiên

 Trong một vài trường hợp mình cần sinh chuỗi ngẫu nhiên dài 8 kí tự, 16 kí tự chẳng hạn. Nếu như ta chấp nhận tất cả các byte trong các kí tự này thì ta sử dụng lớp UUID. Tuy nhiên nếu bài toán của chúng ta chỉ chấp nhận các kí tự alphanumeric (kí số và kí tự trong bảng chữ cái Tiếng Anh) thì chúng ta sử dụng đoạn mã sau đây (Swift 4.2+):


  func randomString(length: Int) -> String {
  let letterList = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  return String((0..<length).map{ _ in letterList.randomElement()! })
}

24/10/2022

View SwiftUI không lấp đầy màn hình

 Có bao giờ bạn bị tình trạng như ảnh chưa?

Cái view màu trắng bên trong không lấp đầy màn hình mà phía trên và phía dưới còn hai dãy màu đen dù cho trong cấu hình bạn đã chọn "Require show full screen" rồi.
Nguyên nhân là do XCode bị cache hay bị lỗi gì đó mà XCode hiểu là bạn đang thiếu cấu hình "Launch Screen".
Tìm hiểu trên mạng thấy mọi người chỉ nhiều cách nào là thêm vào file Info.plist, nào tạo LaunchScreen.storyboard và cấu hình lại "Launch Screen". Tuy nhiên trong trường hợp của mình thì mình chỉ cần gõ chữ bất kì chỗ tên Launch Screen, save lại là vấn đề được giải quyết.


21/10/2022

Lặp lại một công việc gì đó trong 1 khoảng thời gian trong RxSwift

Trong một số tình huống chúng ta cần thử lại một công việc gì đó trong một số lần hay một khoảng thời gian nhất định. Trong RxSwift chúng ta làm điều này thế nào? Đoạn code sau đây sẽ làm lại công việc trong maxRetry lần và khoảng cách giữa hai lần thử lại là retryDelay giây

       observable.retry { errors in
            return errors.enumerated().flatMap{ (index, error) -> Observable<Int64> in
                if error is AppError {
                    let appError = error as! AppError
                    if appError.code == AppError.retryError.code {
                        return index < maxRetry ? Observable<Int64>.timer(retryDelay,
                        scheduler: MainScheduler.instance) : Observable.error(error)
                    }
                }
                return Observable.error(error)
            }
        }
    }
}

Trên đoạn code trên nếu muốn retry lại thì observable cứ quăng error là AppError.retryError thì observable được lặp lại.

20/10/2022

Tắt thanh trạng thái trong iOS

Có những ứng dụng cần tắt thanh trạng thái (status bar) đi thì ta phải làm sao?
Thêm vào file info.plist các dòng sau đây:

 <key>UIStatusBarHidden</key>
    <true/>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
 
 
Dễ không các bạn? Chúc các bạn thành công.

10/10/2022

Swift 5.7: Điểm mới trong if let (Optional Binding)

Trong phiên bản 5.6 trở về trước thì các câu lệnh sau đây sẽ báo lỗi:

func printName() {
let name:String?="Folami"
if let name {
print(name)
}
}

Mà code đúng phải là:

func printName() {
let name:String?="Folami"
if let name = name {
print(name)
}
}

Trong Swift 5.7 thì các bác cứ thoải mái dùng cú pháp như trong đoạn code đầu tiên nha. Cách ghi này gọi là dạng viết tắt của Optional Binding Tuy nhiên có một giới hạn là chúng ta không thể truy xuất đến property của một đối tượng. Điều này có nghĩa là cách viết tắt của Optional Binding không hỗ trợ Optional Chaining. Như vậy đoạn code sau sẽ báo lỗi khi biên dịch:

class Person {
 var name:String?
 init(name:String){
  self.name = name
 }
}
func printName() {
let name:String?="Folami"
if let name {
print(name)
}
}
let author = Person(name:"Folami")
if let name = author.name {
 print(name)
}
if let author.name {
//Se bao loi dong phia tren
print(author.name)
}

24/09/2022

Chuyển vòng lặp for từ Object-C sang Swift

 Hôm qua gặp một cái bug khá vui. Mình và bạn khác nữa làm dự án Port code cũ Object-C sang Swift. Bạn này sau khi kết thúc giai đoạn coding thì rời dự án và mình tiếp tục test và fix bug. Mình chạy test case trên code cũ và code mới thấy kết quả khác nhau. Mình review từng dòng code thấy không có vấn đề gì (tuy cả ngàn LOC nha). Cái mình nghi ngờ nhất là hai vòng for lồng nhau mình chèn code xuất log và phát hiện chính xác nguyên nhân là do cách port vòng for.

Trong Object-C vòng for sau đây:


for (int i = 1; i <= 10; i++)
{
    //do something
}

được chuyển sang Swift như sau:

for i in 1..<11 {
//do something
}
và vấn đề phát sinh khi trong thân của vòng lặp chúng ta thay đổi biến đếm i. Ở phiến bản Object-C thì mỗi lần quay lại vòng lặp biến i được tăng thêm 1 và so sánh 10 xem i đã vượt quá 10 chưa nếu chưa thì tiếp tục thực hiện các câu lệnh bên trong vòng lặp. Ở phiên bản Swift thì 1..<11 là một iterable (xem thêm về IteratorProtocol) nên khi mỗi lần vòng lặp quay lại thì i=iterable.next() và giá trị của i bên trong vòng lặp đã bị ghi đè, huỷ bỏ. Kết quả hai phiên bản chạy hoàn toàn khác nhau.

Trong trường hợp này trong Swift nên dùng vòng lặp while thay cho vòng lặp for.

19/06/2022

Bài 5, Đề Toán Tuyển sinh lớp 10 (Hà Nội), năm 2022

 Đề bài:

Với các số thực không âm x và y thoả mãn $x^2+y^2=4$, tìm giá trị nhỏ nhất của biểu thức $P=x+2y$

Bài giải:

Ta có:

$4=x^2+y^2=(x+y)^2-2xy \le (x+y)^2$

$\Rightarrow x+y \ge 2$

$\Rightarrow P = x+2y \ge 2+y \ge 2$

$\Rightarrow Min(P) =2$

Dấu "=" xảy ra khi $-2xy = 0 \land y =0 \Rightarrow y =0 \Rightarrow x=2$

Vậy $Min(P)=2$ khi $x=2 \land y=0$

Ta cũng có thể tìm $Max(P)$

Áp dụng bất đẳng thức Bunhiacopxski cho hai bộ số (1,2) và (x,y) ta có:

$(1.x+2.y)^2 \le (1^2+2^2)(x^2+y^2)=5.4=20$

$\Rightarrow P =x+2y \le 2\sqrt{5}$

Vậy $Max(P)=2\sqrt{5}$

Dấu "=" xảy ra khi và chỉ khi $\frac{1}{x}=\frac{2}{y} \iff y=2x=\frac{4\sqrt{5}}{5}$