顯示具有 iOS 標籤的文章。 顯示所有文章
顯示具有 iOS 標籤的文章。 顯示所有文章

2020年6月29日 星期一

[iOS] JSON

JSON

JavaScript Object Notation,是輕量級的資料交換語言,與Swift的字典相當類似,使用key對應value,並且可以儲存String、Int、Double以及Array,透過JSON可以很方便的從別的平台取得資料,接著轉換成Swift程式語言可使用的格式。

{
  "a" : "a",
  "b" : 0,
  "c" : 0.5,
  "d" : [1,2,3,4,5],
  "e" : {
    "e1": "e"
  }
}

以上是一個簡單的JSON結構,大括號【 {} 】代表物件,中括號【 [] 】代表陣列,一樣是使用

雙引號代表字串,冒號的左方為key,右方為value。

所以我們使用以上的JSON,拿字串a代表key的話,會取出字串a這個value,依此類推。

通常整個JSON是一個字串,我們可以透過轉換將JSON字串轉換成JSON,舉例來說,我們先使用字串構建一個JSON。

        let jsonString = """
        {
          "a": "a",
          "b": 1,
          "c": 1.1
        }
        """

我們可以到網站上驗證我們的JSON字串是否合法


確認是一個合法的JSON字串後,我們試著將它轉換成Swift可使用的資料格式,

前面有提到JSON其實與字典十分類似,因此你可以將JSON字串轉換成字典。 

        //將JSON字串轉換成Data
        if let jsonData = jsonString.data(using: .utf8) {
            do {
                //透過JSON序列化轉換成自字典物件
                if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
                    print(dictionary["a"]!) //a
                    print(dictionary["b"]!) //1
                    print(dictionary["c"]!) //1.1
                }
            } catch {
                print(error.localizedDescription)
            }
        }



但是透過字典來取JSON其實還是有些麻煩,更好的作法應該是將JSON轉換成物件,不管是Class或Struct的形式均可,因此這邊說明如何將JSON轉換成物件。

首先我們必須要建立一個相同的物件格式,以上面的例子來說

struct MyJSONModel {
    var a: String
    var b: Int
    var c: Double
}

接著我們必須遵循Codable協議

struct MyJSONModel: Codable {
    var a: String
    var b: Int
    var c: Double
}

如此一來你就可以將JSON轉換成這個結構的實體

透過JSONDecoder來將JSON Data轉換成結構的實體

//將JSON字串轉換成Data
if let jsonData = jsonString.data(using: .utf8) {
    do {
        let jsonDecoder = JSONDecoder()
        let myJSONModel = try jsonDecoder.decode(MyJSONModel.self, from: jsonData)
        print(myJSONModel.a) //a
        print(myJSONModel.b) //1
        print(myJSONModel.c) //1.1
    } catch {
        print(error.localizedDescription)
    }
}

當然反過來也可以,你可以將結構實體透過JSONEncoder轉換成JSON Data

let myJSONModel = MyJSONModel(a: "AA", b: 1, c: 0.2)
let jsonEncoder = JSONEncoder()
do {
    let jsonData = try jsonEncoder.encode(myJSONModel)
} catch {
    print(error.localizedDescription)
}



有幾個點必須注意的,你的struct或class定義的屬性,一定要與JSON一致,JSON的Value是整數就必須定義成整數,如果有些時候,這個值可能不存在,就必須定義成可選型別。

變數名稱也必須與JSON的Key相符,若是不相同,則會解析失敗,

有些時候JSON的Key可能與Swift的命名有些衝突,舉例來說有個JSON格式如下

{
    "Name": "Jerry",
    "Age": 18,
}

如果我們想要使用這個JSON,且是轉換成struct或class的話,就得這樣定義

struct User: Codable {
    var Name: String
    var Age: Int
}

但是我們都知道,Swift的命名規則,常數與變數名稱應該為小寫開頭的,因此這樣的命名不是太妥當

你可以一樣將變數命名成小寫,並增加一個enum CodingKeys,且資料型態為String,實作CodingKey這個Protocol。

struct User: Codable {
    var name: String
    var age: Int
    
    
    enum CodingKeys: String, CodingKey {
        case name = "Name"
        case age = "Age"
    }
}

enum的case為你的所有變數名稱,後方則是JSON對應的Key真正的樣子,如此一來,即使JSON的Key與Swift的命名有出入,也可以更換成我們習慣的命名規則。

let jsonString = """
{
  "Name": "Jerry",
  "Age": 18
}
"""

//將JSON字串轉換成Data
if let jsonData = jsonString.data(using: .utf8) {
    do {
        let jsonDecoder = JSONDecoder()
        let user = try jsonDecoder.decode(User.self, from: jsonData)
        print(user.name) //Jerry
        print(user.age) //18
    } catch {
        print(error.localizedDescription)
    }
}

此外,你可以解析JSONDecoder所拋出的例外


            do {
                let jsonDecoder = JSONDecoder()
                let myJSONModel = try jsonDecoder.decode(JSONModel.self, from: jsonData)
            } catch DecodingError.keyNotFound(let key, let context) {

            } catch DecodingError.typeMismatch(let type, let context) {
                
            } catch DecodingError.valueNotFound(let type, let context) {
                
            } catch  {
                
            }



2020年6月17日 星期三

[iOS - Swift] UIColor

iOS用於表示顏色的Class,iOS有提供一些已經有的顏色,也可以使用自己的方法來創建。
UIColor.red
UIColor.blue
UIColor.yellow

let customColor = UIColor(red: 100/255,
                        green: 100/255,
                         blue: 100/255,
                        alpha: 1)

顏色的組成為RGBA,光的三原色,紅綠藍,Alpha則為透明度,每個值可從0~255,總共有256種變化,
可呈現的顏色有 256 * 256 * 256種顏色,幾乎所有的顏色都有辦法顯示。

也可以使用Assets來管理顏色
 
接著透過此方法並輸入你命名的名稱即可取得該顏色
view.backgroundColor = UIColor(named: "MyColor")
此外,你可以透過Color Literal來直接指定顏色,於程式碼區塊輸入Color Literal,並且點選它
點選顏色方塊,就可以直接於程式碼之中選擇你想要的顏色
 

[iOS - Swift] Date的使用方式

Date是專門用來處理有關時間的一個類別。
我們可以簡單的透過以下的程式碼來取得當前時間。

let date = Date()

接著透過DateFormatter來進行時間的轉換,因為我們可能會需要將時間轉換成字串,以便顯示,或者進行處理。

///取得當前時間
let date = Date()
///時間轉換成字串
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
print(dateFormatter.string(from: date))
我們可以透過網站得知一些時間的格式應該怎麽使用

透過設定dateFormat,來讓Date轉換成你想要的時間格式。
如果轉換出來的結果可能會依照語系的不同,可以經由設定語系來更改

///取得當前時間
let date = Date()
///時間轉換成字串
let dateFormatter = DateFormatter()
///設定語系
dateFormatter.locale = Locale(identifier: "zh_tw")
dateFormatter.dateFormat = "MMMM"
print(dateFormatter.string(from: date))

當然,你也可以透過文字轉換回Date

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "zh_tw")
dateFormatter.dateFormat = "yyyy/MM/dd"
if let myDate = dateFormatter.date(from: "2018/12/21") {
    print(myDate)
}
至於日期的增減則可以使用Calendar來處理
let date = Date()
///加三天
let newDate = Calendar.current.date(byAdding: .day, value: 3, to: date)!
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "zh_tw")
dateFormatter.dateFormat = "yyyy/MM/dd"
print(dateFormatter.string(from: newDate))

日期的比較,因為Date有實作Comparable這個Protocol,因此可以很簡單的使用> < = 來進行日期的比較。

let date = Date()
let newDate = Calendar.current.date(byAdding: .day, value: 3, to: date)!
if date < newDate {
    print("Date < NewDate")
}
if date > newDate {
    print("Date > newDate")
}
if date == newDate {
    print("Date == newDate")

2020年1月2日 星期四

[iOS] 讓ScrollView顯示indicators

有時候有些畫面可以捲動,可是使用者不一定知道這個畫面可以捲動,你可以於每次顯示此畫面時,呼叫flashScrollIndicators函式,讓ScrollView相關類別顯示一下Indicators,這樣會讓使用者知道這個頁面可以捲動。

使用效果就會像是這個樣子,可捲動的Indicators會顯示出來。



2019年11月12日 星期二

[iOS] 等寬字體

有時候會需要等寬字體,像是顯示數字時,希望位數相同的可以對齊,若是你設定的字體非等寬字體的話,就會像以下這個樣子。












你可以使用CourierMenlo兩種等寬字體來解決此問題

Courier
























Menlo













2019年10月31日 星期四

[iOS] 文字轉語音

如果你想要讓你的App有朗讀的功能,也就是文字轉語音,使用方式非常的簡單。

首先要import AVFoundation,

接著只需要寫以下的程式碼即可。

2019年10月14日 星期一

[iOS] Swift some 與 Opaque Result Types

Swift5.1之後出現了SwiftUI,學習時發現了一個新的關鍵字some


因此稍微研究了一下有關some的使用方式。

簡單的說當你的Protocol有associatedtype或Self時,Swift無法得知你的具體類型為何。

我們先來看一般狀況的Protocol,我們有個Animal的Protocol,並且有兩個struct去實作它。

此時我們寫一個Func,可以取得一個Animal

一切都很美好,但是如果我們想在Protocol加入associatedtype,像是以下的程式碼。

接著你會發現原本的取得Animal方法被發出警告訊息

原本的做法,你必須改成以下的寫法


使用時也必須指定資料型態


整體來說並不是太方便,因此多了some關鍵字,我們只需要將原本的程式碼改成以下的樣子

如此一來就可以很方便的使用,使用時也不必指定資料型態。


但是要注意的是,若是你的Func有多種類回傳值,分別是不同的實作該Protocol是不行的。


簡單的說some會依照你的回傳值來判斷是哪個類型實作了該Protocol,你不用特別指定哪個類型,而是依照你回傳的值來決定。

舉一個比較常見的例子,Equatable這個Protocol,它的定義如下。


你必須實作==這個Func才算符合Equatable這個Protocol,我們都知道Int有實作該Protocol,因此我們寫一個Func,來隨機產生一個Int,可是我們希望回傳的資料型態是Equatable。



經過上面的例子我們知道是不行的,因為Equatable裡面有使用到Self,因此必須加上some關鍵字。

我們加上some之後,我們繼續增加另一個產生字串的Func,一樣回傳Equatable。

接著我們呼叫這兩個方法,將它們的值取出。


會發現,兩個都是Equatable資料型態,那我們來使用==方法看看。


事實上是不行的,因為雖然表面上都是Equatable,實際上一個是Int,一個是String,雖然我們看不出來,但是Xcode很聰明的看出差異了。

但是如果來源都是同一個Func所Return的值,Xcode會視為相同的。


如果你有兩個Func所Return的值是相同的,Xcode也會認為不同哦,它只認Func,不認回傳值。


2019年9月9日 星期一

[iOS] UITableView - 基礎2

透過基礎1中我們學會了如何使用UITableView。

若是還沒看基礎1,可以透過以下連結前往

基礎1


接下來我們可以使用UITableViewDelegate來取得使用者點選了哪個Cell。

我們先建立簡單的UITableView,可以透過基礎1的結果繼續往下做。

接著在我們的ViewController,透過extension來實作UITableViewDelegate



此時你會發現Xcode並沒有任何變化,因為UITableViewDelegate這個Protocol,所有的func都是可選的,因此就算你一個func都沒有實作,它也認為你已經實作了此Procotol。

但是我們會需要知道使用者點選了哪個Cell,我們可以在Xcode輸入以下的文字

tableviewdid

接著靠Xcode的自動完成功能,選擇我們所需要的func


tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

為UITableViewDelegate Protocol的其中一個func,當使用者點選了任何一個Cell時,將會觸發,會回傳兩個值,分別是你所點選的tableView是何者,以及所點選的indexPath,接著我們將func寫入以下程式碼,使用者點選時會印製log出來。



最後不要忘記在viewDidLoad指定delegate 哦,以下為完整程式碼。



你可以試著執行看看程式,點選其中一個Cell的時候,應該會有訊息印製出來哦。


[iOS] UITableView - 基礎1

UITableView,是一種表格化顯示的View,可以從各式各樣的App當中看見它的身影,是十分常見的一種View。

這邊來介紹最基本的使用方式,首先先開啟一個新的專案,並且於StoryBoard中,加入UITableView,並且設置簡單的Constraint,將UITableView佔滿UIViewController。


接著,我們建置IBoutlet,將UITableView與我們的UIViewController class做關聯,以下我們命名為tableView。


下一步,如果要使用UITableView,我們必須實作UITableViewDataSource這個Protocol。

因此我們加入extension,讓我們的ViewController去實作UITableViewDataSource,此時你會發現Xcode自動發出警告,若是要實作這個Protocol,必須實作一些方法


按下Fix後,XCode會自動幫你產生所需要的程式碼。

必須要實作兩個方法。

tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

你必須告訴tableView,你要顯示幾個Row

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

你必須告訴tableView,每個Row所顯示的Cell

接著我們先切回StoryBoard,並且搜尋UITableViewCell,將UITableViewCell拖曳到UITableView裡面。


接著我們選擇這個Cell,然後於右邊的屬性配置區,輸入這個Cell的Identifier,我們將它命名成『MyCell』。


下一步我們可以回到程式碼,將不足的部分補齊,首先我們告訴TableView,我們需要10個Row。

接著我們將下一個程式碼也補齊,我們透過剛才於Storyboard設置的Identifier來取得Cell,並且設置顯示的文字。

最後於viewDidLoad,將tableView的dataSource設置為我們的ViewController,以下是完整的程式碼。

以及執行結果。

以上就是TableView,最基本的用法,要使用就必須實作UITableViewDataSource這個Protocol。

接下來可以看基礎2學習如何使用UITableViewDelegate來捕捉使用者點選了哪個Cell哦。

基礎2

2019年8月30日 星期五

[iOS] PropertyWrapper屬性包裝器

PropertyWrapper,屬性包裝器,透過屬性包裝器,來針對屬性進行包裝。

舉例來說,我們希望某個變數它永遠都是大寫。


我們可以在使用的時候再將它轉換,可是感覺有些麻煩,因此我們可能會寫成這樣


但是這樣寫初始化的時候並不會進入didSet,因此只能很勤勞的在建構子也加入轉換大寫的程式碼。


終於大功告成了,但總的來說並不夠美觀,因為如果有更多的屬性,那不就要在每個屬性的didSet,與建構子中加入程式碼,此時,屬性包裝器就可以派上用場了。

我們建立一個Struct,命名成Uppercased,並在它的上方加入@propertyWrapper關鍵字。

接著Xcode會提示說,propertyWrapper需要有一個名為wrappedValue的屬性,我們將這個屬性加入,並且做一些處理。


程式碼做的事情就是將wrappedValue在set的時候轉換成大寫存在value變數之中,get的時候就取出轉換成大寫的value變數,基本上跟上方獨立處理是差不多的,但是這時候神奇的事情發生了,我們回到Data結構裡面,把title前方加入@Uppercased來修飾。



這樣這個title就被我們自定義的屬性包裝器包裝過了,此時要存取這個屬性都會透過包裝器來存取,就永遠都是大寫了。

有一個例子我覺得還不錯,存取UserDefault就可以使用屬性包裝器。


存取的時候透過屬性包裝器直接存入到UserDefault之中,就可以不需要寫一堆重複的程式碼了。

2019年1月6日 星期日

[iOS] 利用UIImagePickerController 取得相簿內照片

有時候可能會需要取得使用者手機內的照片,這時候就可以使用UIImagePickerController來取得。

假設是從使用者的相片庫取得,可以參考以下的程式碼。



接著要實作兩個Protocol,來符合UIImagePickerController的Delegate。


如此一來就可以完成一個簡單的取用使用者照片的程式。

如果你想要從使用者的相機取得照片,可以參考以下的程式碼。



記得要將Privacy - Camera Usage Description加入到Info.plist裡面哦


2018年6月26日 星期二

[iOS] Singleton的產生語法

有時候整個App生命週期可能需要某幾個只有一個實體的Class,

這時候可以使用Singleton來達成,以下是產生Singleton的程式碼。

Swift


Objective - C



2018年6月14日 星期四

[iOS] 利用xib來製作客製化View

圖片能點擊放大

1. 新增一個客製化的View,命名成為你需要的名稱,且繼承於UIView


2.新增一個同名的xib,此時你的專案應該會有兩個檔案






3.  開始設計你的View,這邊簡單的放入一個Button,並且改為綠色


4. 點選上方的File's Owner類別後,將右邊的Custom Class設置為你的Class名稱。



5.此時你應該可以加入IBoutlet與IBAction了,我們加入一個IBAction,在Touch Up Inside時會印出Log。


6. 此時你的程式碼應該只有這樣


7. 接著我們要override兩個事件,init(frame: CGRect)以及init?(coder aDecoder: NSCoder),此時你的程式碼應該如下。


8. 增加一個loadXib的方法,並填入以下的程式碼

這邊主要是使用nib載入xib的View,並加入到這個Class的View,在設置Autolayout讓畫面呈現。

將loadXib方法加入到剛才override的事件之中,此時完整程式碼應該如下。



如此一來,你就能正常使用這個客製化View了。

可以直接在StoryBoard上面,加入一個View,並將Class設置為你的客製化View



 當然,你也可以使用Code產生這個View後在加入到當前頁面上。


2017年11月16日 星期四

[Objective-C] Class property - 類別屬性

XCode8以上在Objective-C增加了class關鍵字,你只需要在@property增加此關鍵字即可讓此屬性變成Class Property。

首先先在.h宣告一個class property。


接著在.m實作Getter與Setter。
這樣你就可以使用這個class property了,如果這個屬性是readonly的話,可以只實作Getter就好。

2017年11月14日 星期二

[iOS] 在專案中使用OpenSSL的方法

首先先下載OpenSSL-for-iPhone,點選Clone or Download,並下載到你的電腦裡面。

接著打開終端機,並且前往到剛才下載的資料夾內。

接著輸入此指令


./build-libssl.sh

等待安裝OpenSSL完成,當完成時,可以先打開剛才下載的專案,並且執行,若是安裝成功應該可以跑起來。

























若是成功了,你可以現在試著開啟自己的專案,並加入OpenSSL,首先先新增一個專案

接著打開剛才的資料夾,把include複製到新的專案資料夾內。














接著一樣在資料夾中,找到lib的資料夾,把libssl.a跟libcrypto.a加到新的專案中













接下來切換到Bulid Settings,搜尋Library Search Paths,並添加以下兩個參數
$(inherited)
$(SRCROOT)


接著一樣在Bulid Settings,並搜尋Header Search Paths,並且參數為include,並將改為recursive,接著上面的Always Search User Path設定為YES。

接下來,你可以把之前的資料夾內的FSOpenSSL複製到你的專案,並且跑看看,若是成功的話,那你的專案就可以使用OpenSSL了。


2017年11月13日 星期一

[iOS] 有關UITextField反白區域與游標位置

如何得知目前使用者的游標位置或者是反白區域,可以參考以下的程式碼。

Objective-C



Swift



而如果你需要改編游標位置或者是反白區域,可以參考以下的程式碼。

Objective-C



Swift


2017年8月21日 星期一

[Swift] Associatedtype - Protocol中的泛型

假設我們有個需求是當實作某個Protocol時,其中有些方法傳入的資料型態可能是由實作者來定義的,就可以使用Associatedtype。

舉例來說,有個Animal的Protocol,在實作的時候,實作者可以定義這個動物吃的資料型態,並實作吃食物的方法,以下可以參考程式碼。


此外,如果想要將泛型範圍縮減一點也是可以的,繼續拿這個例子來說,假設我們想定義一個寵物的Protocol,而裡面必須要是有實作過動物的資料型態才可以,你可以參考以下的程式碼。


2017年7月20日 星期四

[iOS] DateFormatter要注意的問題

要將Date轉成字串你可能會使用DateFormatter來轉換,

但是,DateFormatter有一個必須要注意的地方,很多人可能會忽略了這一點,

可以參考一下以下的程式碼。


取得今天的日期,使用DateFormatter將Date的年份取出,並印出。

可以期望會印出2017年,因為今年是2017年,一般來說的確也會印出2017。

但是有可能有例外發生,當使用者自行設定手機的歷別時,就會發生問題了。

在設定 > 一般 > 語言與地區 > 行事曆,這邊可以更改歷別

當你在執行一樣的程式碼的時候,你會發現不是印出你熟悉的年份了



如果你還是想印出2017年,你就必須將DateFormatter指定為西曆,詳細可以參考以下程式碼。

2017年3月10日 星期五

[Objective-C] 加入事件到手機行事曆之中

首先,你必須先在你的APP專案中設定提示訊息,若是你要存取使用者行事曆時,會顯示的訊息,而這是必要的步驟,若是沒加入此提示訊息,執行時將會有錯誤。

設定的步驟可以參考以下的圖片。


第四步驟要加入的值為Privacy - Calendars Usage Description,Value可以不填入任何資料。

此時,若是你的APP要存取行事曆時,就會跳出提示訊息提醒使用者,若使用者同意讓你存取,就可以進行存取了。

接著可以開始寫程式了,要先在import以下的東西才能使用。


初始化EKEventStore之後,執行以下的方法,並填入兩個參數。



EKEntityType可以填入以下兩個其中之一,會依照輸入的不同,而在行事曆裡面建立不同的種類

EKEntityTypeEvent(事件)
EKEntityTypeReminder(提醒)

加入事件到行事曆的可以參考以下的程式碼


實際執行時,你可以確認行事曆是否有加入剛才加入的事件



























此外,如果你想使用APP刪除此事件,可以參考以下的程式碼,透過剛才加入事件的辨識符號來刪除。


2016年9月14日 星期三

[Objective-C] 使用xib來製作客製化的View

有時候你會需要一些客製化的View,你可以繼承UIView,在使用程式碼來刻出你想要的樣子。

但是實在不夠直覺,你可以試著使用xib來達成這個需求。

首先我們先創建一個繼承自UIView的檔案,名為MyView。

接著我們也創建一個名為MyView的xib檔。




















接著我們點選我們的xib檔,並選擇File's Owner,

設定Custom Class為我們的MyView













此時你可以在xib上面加入一些元件,也可以進行IBAction與IBOutlet的相關設定了。

接著,你必須到MyView.m檔裡面加入一些程式碼。

我們可以透過快速輸入來產生程式碼的架構,

我們選擇initWithCoder。





















用拖曳的形式加入到你的程式碼之中,此時你的程式碼長得像這個樣子。










接著將你的程式碼改成這個樣子



如此一來你的xibView就會在MyView載入的時候,也加入到裡面去,

這麼一來你就可以很方便的透過視覺化介面來拉屬於你的View。

最後只需要簡單的在VC上面加入一個UIView,並指定Class為MyView就可以了。