[Golang]關於Slice在Append的一些發現

image

前言:

當初主要是RUST在官網上提出他們可以避免掉std:vector.push_back造成的referene 問題. 於是我也很好奇,究竟Golang會怎麼樣處理這樣的問題. 也由於Go本身把vector拿掉,我們就用Slice來試試看.

筆記:

image

Slice 本身的結構包含資料本身,長度(len)與容量(cap),根據Slice Internal Document裡面提到的.而且操作slice的append的時候,會根據你目前的容量(cap)來決定是否要重新分配記憶體位置.

比起std::vector好的是,如果記憶體重新分配了,原先參照的參數不會得到空的記憶體位置,而會變成是複製的內容. 但是要注意的是,參照的變數就不會跟著變動了. 這聽起來就是比較安全一點,不過程式不會造成pointer to null並不代表比較好,因為在這種狀況下.所參照的數值已經被修改,你可能會遇到更不能預測的問題.

所以比較優雅的方式,還是事先要保留足夠的資料.避免append造成的資料重新建立.

奇怪的狀況,cap增長的大小根據compiler的不同

我本來是很清楚這樣的狀況,直到我把我以下的程式跑在本地端(Mac/Win)還有遠端的Golang Playground發現結果不一樣了.

是的! 靚過第一次slice append之後,cap(slice)增長的數值竟然不一樣?? (Playground是2,本地端是1) 一樣的狀況.類似的操作在c++ std::vector 就沒看到 (Win/Mac/Coliru online compiler) 增加過後的的cap都維持為”1”. 這裏有參考的C++程式碼.

於是我在Stackoverflow詢問了這樣的問題,也引起了一些人的注意,幫我把問題發到了Golang上面.雖然沒有辦法說服大家把這樣類似的問題放入spec或是warning,但是真的提醒大家,真正在使用slice的時候,必須像使用std::vector一樣的小心.最好的方式是不要參照,如果真的要參照的話,也建議使用保留的slice大小來避免記憶體重新的分配所造成的參照失效.

以下是完整的Golang 測試程式碼

  
package main
 
import "fmt"
 
func main() {
	var a []int
	var b []int
	fmt.Printf("a len=%d, cap=%d \n", len(a), cap(a))
	a = append(a, 0)
	b = append(b, 0)
	p := &a[0]
	
	fmt.Printf("a[0] = %d pointer=%d, len=%d, cap=%d, p = %d \n", a[0], &a[0], len(a), cap(a), *p)
	a[0] = 2
	fmt.Printf("a[0] = %d pointer=%d, len=%d, cap=%d, p = %d \n", a[0], &a[0], len(a), cap(a), *p)
	/*
		a[0] = 0, p = 0
		a[0] = 2, p = 2
	*/
	var c []int
	var d []int
	fmt.Printf("c len=%d, cap=%d \n", len(c), cap(c))
	c = append(c, 0)
	d = append(d, 0)
	p2 := &c[0]
	fmt.Printf("a[0] = %d pointer=%d, len=%d, cap=%d, p2 = %d \n", c[0], &c[0], len(c), cap(c), *p2)
	c = append(c, 1)
	c[0] = 2
	fmt.Printf("a[0] = %d pointer=%d, len=%d, cap=%d, p2 = %d \n", c[0], &c[0], len(c), cap(c), *p2)

	/* 
		c[0]=0, p2 = 0
		c[0]=2, p2 = 0
	
	  in http://play.golang.org/p/DuClFZt2cK, the cap increasement by machine dependency.
		c[0]=0, p2 = 0
		c[0]=2, p2 = *2*
	  
	*/
}

[UNIX][python][Golang][程式設計週記]20141227

前言:

今年年底到數第二週,可以開始深入研究一些自己有興趣的東西.本週主要研究signal的處理,regex與新程式語言RUST學習,當然其中也有一些新的MOOCs學習.加上這個禮拜週六要補班,所以整個內容應該會比較多一點.

筆記:

  • [Unix]關於Signal PIPE 更深入的研究
    • 前言:
      • 雖然加上了signal pipe的handler但是並沒有真正的測試到類似的狀況.
      • 這個禮拜應該會花一些時間好好的研究詳細的內容.
    • 筆記:
      • 關於Signal:
        • signal就是去接受或是傳送process間的溝通方式.系統設定好,也比較為人所知的就是 SIGINT (就是ctrl + c), SIGTERM(process 結束)或是 SIGKILL(被 kill,不過系統預設是不能catch 這個signal). 而這裡探討的是如何把接受到signal要做的一些處理做起來.這裏有更多的說明
      • 如何處理Signal:
        • 基本上會收到任何signal,表示你的程式正在收到不可預料的狀況(以系統的signal為例),但是無法明確的了解哪些問題的發生.通常會建議把一些資源回收後,準備重啟的相關動作.
      • [12/22]關於測試sigaction 的部分:
        • 可以使用 kill -s (signal) process_id 來傳送signal
        • 不過並不是完全可以接收的到.
          • 以下是接受的清單:
            • SIGINT (02)(handle ctrl + c signal)
            • SIGSEGV (11)
            • SIGALRM (14)
            • SIGTERM (15)
            • SIGSTOP (17)
            • SIGTSTP (18)(handle ctrl + z signal)
          • 以下接收不到:
            • SIGSYS (12)
            • SIGPIPE (13)
            • SIGCONT (19)
      • [12/23]於是我把我發現的事情,整理過後試著去stackoverflow詢問.得到了回應是他們測試是可以的,可能是我底層元件出了問題.
        • 經過測試真的如網友回應的,看來底層的元件有把SIG_PIPE收走,造成我在上層無法接收加以處理. 得繼續研究如何解決類似的問題…..
      • [12/24]最後網友提出解決方式就是在3rd party library 後面去加入sigaction,這樣就可以了.
      • 參考:
#include 
#include 
#include 
#include 

void handle_pipe(int sig)
{
    printf("SIG_PIPE happen, error code is %d", sig);
    exit(0);    
}   

int main(int argc, char **argv)
{
    struct sigaction action;
    sigemptyset(&action.sa_mask);
    action.sa_handler = handle_pipe;
    action.sa_flags = 0;
    //not work
    sigaction(SIGPIPE, &action, NULL);   //Not work with kill -13 process_id
    //works well
    sigaction(SIGINT, &action, NULL);    //work with kill -2 process_id
    sigaction(SIGSEGV, &action, NULL);   //work with kill -11 process_id
    sigaction(SIGALRM, &action, NULL);   //work with kill -14 process_id
    sigaction(SIGSTOP, &action, NULL);   //work with kill -17 process_id

    while(1)
    {
        sleep(1);
    }
}

</pre>            
            
- [Python][Unix]深入研究regex (Regular Expression) (1)
    - 前言:
        - 主要是在伺服器的log上面,忽然有需要抓出某些特定的資訊.由於因為限定某些時間之內,所以無法改server,所以只好開始搞搞regex.
        - 不過當時手邊沒有一個可以快速找到內容並切輸出的內容regex語法,所以當時還是用一些巨集加上檔案的轉換才搞定.
        - 東西忙得差不多,決定把這個整理成一個python檔案.可以幫助以後快速的分析並且抓出需要的資料.
    - 筆記:
        - 首先關於regex,根據[鳥哥Linux的私房菜](http://linux.vbird.org/linux_basic/0330regularex.php)上免得說明.其實可以直接透過grep來完成.不過我沒辦法完成太複雜得,而且又牽扯到字串內的逃逸字串問題,所以這部分僅僅帶過.
            - grep -n 'REGEX' input_file
       - 後來決定使用python的[regex](https://docs.python.org/2/library/re.html)功能,其實提供的功能可以替換跟找出來並且轉換成list.已經很夠用了.
       - 以下是一段python找出檔案內電話資料格式的範例(以台灣室內電話與行動電話為例)      
    - 相關資源:
        - Java script 去顯示regex 語法示意圖
            - [http://jex.im/regulex](http://jex.im/regulex)
        - regex eval可以幫你找出特定文字內符合你輸入的regex內容.
            - [http://regexpal.com/](http://regexpal.com/)

 #python sample
import os
import re

 # filename variables
filename = 'data//test_regex.txt'
newfilename = 'result.txt'

 # read the file
if os.path.exists(filename):
    data = open(filename,'r')
    bulkemails = data.read()
else:
    print "File not found."
    raise SystemExit

 # regex to get phone
 # (01)2345-6789 , (01)23456789
 # 0123456789 
 # 0911-234-567

r = re.compile(r'(\b(((\d{10})|([\(]??0\d{1}[\)]??\d{4}[\-]??\d{4})|(0\d{3}[\-]??\d{3}[\-]??\d{3})))\b)')
results = r.findall(bulkemails)
emails = ""
for x in results:
    print str(x)+"\n"       
- [Python]關於raw string的用法與轉換 - 前言: - raw string 是python 裡面代表著原始字串的內容,其中不會將逃逸字串作轉換 (ex: \" -> ") - 在regex裡面,我們需要最原始的字串內容來表達搜尋的資料. - 這邊紀錄一下關於字串轉換這裡會遇到的問題. - 筆記: - 在這一篇的[stackoverflow裡面](http://stackoverflow.com/questions/2428117/casting-raw-strings-python),其實有不少的方式可以解決這件事情. - 有人提出可以透過 string.encode('string-escape') 但是對於這邊的系統會出現字串加上了unicode字元,就算改成string.encode(''unicode-escape')一樣不行. - 只能夠過字元 mapp來達到簡單的轉換,原始碼來自同一個網頁....
                                               
escape_dict={'\a':r'\a',
           '\b':r'\b',
           '\c':r'\c',
           '\f':r'\f',
           '\n':r'\n',
           '\r':r'\r',
           '\t':r'\t',
           '\v':r'\v',
           '\'':r'\'',
           '\"':r'\"',
           '\0':r'\0',
           '\1':r'\1',
           '\2':r'\2',
           '\3':r'\3',
           '\4':r'\4',
           '\5':r'\5',
           '\6':r'\6',
           '\7':r'\7',
           '\8':r'\8',
           '\9':r'\9'}

def raw(text):
    """Returns a raw string representation of text"""
    new_string=''
    for char in text:
        try: new_string+=escape_dict[char]
        except KeyError: new_string+=char
    return new_string
- [RUST][MOOCs] 新的系統程式語言 RUST 線上課程與資料 - 前言: - 主要是[FB MOOCs社團上面的推薦](https://www.facebook.com/groups/courserazh/permalink/852795524760307/)的[課程作業系統](http://rust-class.org/index.html),但是特別的是用RUST上課.所以順便來看看號稱"安全,支援並行並且實用"的程式語言是什麼樣的架構. - 話說,介紹網頁寫得相當的棒.讓我引用原文從[官方網站](http://www.rust-lang.org/) - **Rust** is a systems programming language that runs blazingly **fast**, **prevents** almost all **crashes***, and **eliminates data races**. - 筆記: - 這裏主要只紀錄一下相關資訊,其他比較深入的內容可能就會另外弄成一篇. - 相關資訊: - [線上課程- OS - 使用RUST](http://rust-class.org/index.html) - [RUST官方網站](http://www.rust-lang.org/) - [trello RUST rush task](https://trello.com/b/uwzd0qUZ/rust-rush) - [MOOCs] 模型思考開課 - 有中文字幕的Model Thinking 開課一段時間,看了幾個slide挺有趣的.似乎可以幫助思考邏輯的提升. - [課程在這裡](https://class.coursera.org/modelthinkingzh-001)... 雖然有點晚~但是知識才是重點.... :) - [Python] 關於更多的python程式介紹網頁... - [https://inventwithpython.com/chapters/](https://inventwithpython.com/chapters/) - [Android][這一篇文章](http://blog.danlew.net/2014/11/26/i-dont-need-your-permission/)提到Android Intent其實藏有許多的問題 - 在於Intent不需要使用者關於權限的同意.所以即便項範例中舉例說每天半夜盜用妳電話打到某個地方.你也完全蒙在鼓裡. - 不過這篇文章受到大家的注意的是,英文翻譯的問題,最後竟然是由母語是英文的外國人來做翻譯: - The reason you need permission is because with this code you can initiate a phone call at any time without user action! If my app had this permission I could be calling 1-900-CAT-FACTS at 3 AM every morning and you'd be none the wiser - [Golang] 有趣的網址收集,大多是從Golang.tw的討論群組上看到的 - [這一篇介紹](http://jasonwilder.com/blog/2014/02/04/service-discovery-in-the-cloud/)許多有趣的Opens Source Services Discovery 其中相當多是Go寫的 - kite - A RPC services :[介紹網址](http://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/)[Source code](https://github.com/koding/kite) - 順手把Go 從1.3升到1.4,不過會發現許多library有不能與1.4共用.所以go\src下面幾乎所有的檔案都得砍掉重新抓. - 錯誤訊息: "... object is [darwin amd64 go1.3 X:precisestack] expected [darwin amd64 go1.4 X:precisestack" - Gin - A small REST microserver :[介紹網址](http://txt.fliglio.com/2014/07/restful-microservices-in-go-with-gin/) :[Source Code](https://github.com/gin-gonic/gin) - 感覺比[martini](https://github.com/go-martini/martini)更小.. 還得多多的實驗.不論如何.. 有了更多的選擇.... - 找尋的時候,發現有新的web framework [flotilla](https://github.com/thrisp/flotilla) 根據作者在reddit上面的講法,他希望能做出更具有延展性的Web Framework. Engine是可以抽換的. - [作者在reddit的討論](http://www.reddit.com/r/golang/comments/2hg50x/flotilla_set_your_fleet_afloat/) - [介紹網址](https://thrisp.github.io/flotilla/) - [Facebook Go Group](https://github.com/facebookgo/)隱藏的群組,不過有不少程式碼在Github上面. - 開始找一些可以解釋Golang比C/C++好的文章,以下是一些列表: - [Go: 90% Perfect, 100% of the time.](http://talks.golang.org/2014/gocon-tokyo.slide#1) - [Hacker News上面討論C跟Go的比較](https://news.ycombinator.com/item?id=4110480) - [某個人把php搬移到Go的心路歷程](http://tech.t9i.in/2013/01/why-program-in-go/) - [Powered by Go,介紹更多Go比起C/C++的優勢](http://talks.golang.org/2013/oscon-dl.slide#1)

[C][RUST][Python][Go]關於vector的push_back造成的記憶體參考(reference)問題

image

前言:

很基本的概念,是從RUST官方網頁在介紹他的記憶體管理的部分看到的.覺得是很有趣的vector與記憶體處理的問題,由於RUST有比對它的程式語言設計架構,於是很好奇地把其他手邊常用的程式語言找了一下相關的範例.

主要問題(C/C++/ObjectC)

  • 主要是講解,說在vector裡面的記憶體管理其實有一些技巧.尤其是在push_back的部分,每次的push_back如果目前的大小超過他的容量,就會放棄目前的記憶體位址,而去建立一個新的vector記憶體.而原本的記憶體位置就沒使用變成了garbage.
  • 如此一來會造成原本去參考v[0]的記憶體位置變成了garbage,而會crash.
  • 這邊可以參考vector的push_back說明.
  • 這裏在ObjectC與C/C++結果不同,他不會crash但是會沒值.(ObjectC原本設定概念)
  • 在C/C++/ObjectC解決方式:
    • 其實只要先把記憶體保留起來,就可以解決這樣的問題. vector.reserve(specific_size);
  
#include 
#include 
#include 

int main(int argc, const char * argv[]) {
    //Init new vector here
    std::vector<std::string> v;
    //v.reserve(128); could resolve this issue, 128 is arbitrarily value.
    
    //Put first element "hello" v: "Hello"
    v.push_back("Hello");
    // x refer to v[0] which is "Hello"
    std::string& x = v[0];
    
    //Push new element but size will over capacity (default is zero, after first push become 1)
    //So whole memory will deprence and create new memory size =2
    //Refer to http://en.cppreference.com/w/cpp/container/vector/push_back
    v.push_back("world");
    
    // Old reference memory aleady become to garbage, so app crash (depends OS)
    std::cout << x;    
    return 0;
}
</pre>

**在RUST方面**
    
- 根據[RUST官方網頁](http://www.rust-lang.org/)在介紹他的記憶體的管理方面,由於它定義兩種資料結構mutable 跟 let (這裏跟swift有點像).所以根據以下的程式碼,會造成編譯的時候不成功.

  
fn main() {
    let mut v = vec![];
    v.push("Hello");
    //let x = &v[0];  Cannnot compile. because the mutable variable cannot assign to static value.
    let x = v[0].clone();
    v.push("world");
    println!("{}", x);
}
**在Python的部分** - 沒有找到比較像vector的資料結構,我使用list來使用.我也有用codeskulptor來查看[視覺化(Viz mode)](http://www.codeskulptor.org/viz/index.html)的結果. - 在python內有分成兩種方式來參照(reference),如果你參照的是unmutable通常是使用copy,如果是參照mutable就會使用bind.而且整個list變大也不會影響參照的變數. - 這邊主要是python varaible assignment比較不一樣,有比較多的討論可以看: - [How do I write a function with output parameters (call by reference)?](https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference) - [[stackoverflow]How do I pass a variable by reference?](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) - 以下一段原文quote很值得了解: - "the parameter passed in is actually a reference to an object (but the reference is passed by value)" - ""some data types are mutable, but others aren't"
  

# Example in assign to first.
list_a = list()
list_a.append("hello")
item_b = list_a[0]   #copy value list_a first element to item_b, not point to.
list_a.append("world")
print item_b  #hello

# Example in bind to whole list.
list_a = list()
list_a.append("hello")
item_b = list_a    #item_b bind to list_a
list_a.append("world")   #in codeskulptor memory not relocate nd continue.
print item_b       #still "hello"

[iOS][Python][unix][golang][程式設計週記] 工作上的一些雜事筆記20141219

前言:

在上完一個禮拜的Intel課程後,本週可以在辦公室專心做事情.可以專心的好好的把工作進度來超前一下.加上coursera的課程都上完了,應該可以有更多的時間可以好好的看看. 本週重點是學習iOS HealthKit 跟 etcd,當然還是有工作上管理伺服器的一些事情…..

筆記:

  • [Unix] 如何增加一個客製化的服務(custom service)
    • 前言:
      • 新增一些伺服器,所以要把舊的伺服器上面的一些服務搬過來.
    • 流程:
      • 複製相關的shell script 到 /etc/default 與 /etc/init.d
        • 這裡要注意,透過windows檔案複製的話會出現”/bin/sh^M : bad interpreter”,解決方式可以參考這裡
        • 要使用dos2unix 去轉換這些script
      • 增加一些設定檔script到 /etc
      • 記得用”initctl reload-configuration”把這些services重讀,參考這裡
  • [iOS] 關於錯誤“Capturing [an object] strongly in this block is likely to lead to a retain cycle”
    • 前言:
      • 因為HealthKit都在搞Async process所以經常在GCD的過程中去使用原先的self process,所以容易產生這個問題.
    • 原因:
      • 根據stackoverflow上面的解釋,主要原因是因為block會保留一份在裡面,如果保留的是self就會造成循環的持有.
    • 解決方式:
      • 加上以下的部分就可以了
__weak typeof(self) weakSelf = self;

[someprocess setCompletionBlockWithSuccess:^(Operation *operation) {
    [weakSelf someOperationInSelf];

} 
  • [iOS] 關於IPWORKS整合
    • 前言:
      • 公司在用的3rd party component,不過每次整合都會忘記,紀錄一下.
    • 步驟:
      • copy IPWORKs, libSSL
      • Add related framework:
        • libz.dylib
        • libssl.a
        • libcrypto.a
      • Add “Preprocessor Macros” in debug
        • IPWORKS_MINSIZE
        • INCLUDE_IPWORKS_XMPP
      • Change “C++ compiler setting in Apple LLVM 6.0 - Language ++”
        • C++ Language Dialect -> Compiler default.
        • Standard Library -> Compiler default.
  • [Go] 準備好好研究一下etcd
    • 前言:
      • 主要起因是因為這個一月份的Golang聚會,裡面有提到etcd很適合作為IOT(Internet Of Thing)的資料庫,所以打算開始survey.看看是不是真的能讓速度快一點.
    • 筆記:
      • 基本上etcd是一個相當快速的key pairing 資料庫,可以透過http直接存取.
      • 其實發現etcd有以下的幾個優點:
        • 可以透過http來讀取與存取. (讀取直接打網址,存可以用Put跟Post)
        • 雖然是Key Pairing Database,但是還是存有index.所以可以記錄之前的資料.也可以透過wait=true達到key-value observing的效果.
    • 參考:
  • [iOS] 關於HealthKit的筆記
    • 玩HealthKit到現在,其實有點困難必須得承認就是對於單位與測量數值的標準化.
    • 簡單的說:
      • 你想要量個血壓,你就得知道你要量血壓單位名稱.還有血壓數值一般轉換的方式.
    • 舉例而言:
      • 你現在需要量血壓,血壓有兩種數值收縮壓(Diastolic)與舒張壓(Systolic),這時候你需要知道以下一些東西:
        • 舒張壓的資料型態(Type)是 HKQuantityTypeIdentifierBloodPressureDiastolic
          • HKQuantityType *DiastolicType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic];
        • 舒張壓的單位是(millimeter Of Mercury)
          • HKUnit *DISUnit = [HKUnit millimeterOfMercuryUnit];
        • 接下來,還有取得資料的格式與data formaater的翻譯還沒有.
      • 應該會把這個部分整理一下,變成一篇教學.畢竟網路上教學算很少的.
    • 參考:
  • [Unix] 如何在crontab 裡面加入啟動系統服務的程式碼
    • 問題:
      • 想要從crontab裡面透過shell script去啟動背景服務,但是都會發生啟動失敗.
    • 原因與解決方法:
      • 權限的問題,原本在script裡面直接使用
        • service back_server_foo start
      • 發現會失敗,於是改成
        • root service back_server_foo start
      • 如此一來不會有失敗的訊息,但是還是無法正確的啟動.必須要改成
        • sudo /etc/init.d/ back_server_foo start
      • 這樣才會正確地執行成功.
  • [C++] 關於C++回傳char*的討論與挑錯
  • [Unix]針對SIGPIPE的繼續研究

[iOS] HealthKit的初體驗..

image

前言:

最近開始仔細瞭解HealthKit,發現使用上並沒有那麼的直覺.(可能是我對於許多醫療單位沒有那麼清楚的關係 XD) 使用上有一些要注意的與需要瞭解的部分,稍微做一些紀錄.

筆記:

[基本概念]

  • 到目前為止,HealthKit只有iPhone可以用,並且要有iOS8.所以iPad執行程式會失敗.
  • 每一個資料有所屬的資料格式數量(HKQuantity)與該數量的格式(HKQuantityType),而數量(Quantity)本身與單位的格式(HKUnit)有關.
  • 必須要清楚地瞭解,存取的資料數量單位與單位的格式.
    • 比如說,身高要確認是用cm還是inch,體重是使用pound還是kg.
  • 每一個存取都與使用者權限有關,去拿使用者不開放的資料,就會引發錯誤.
  • 所有的動作都是Async的方式:
    • 這邊比較麻煩的是,如果需要抽象化的話可能要把async改成sync這邊可以參考這邊的內容

[基本資料欄位]

  • 關於資料欄位舉例而言,要敘述關於血壓的舒張壓,你就得要撰寫以下的部分:
    //敘述你的血壓單位是 mmag mullumeter of mercyry unit
    HKUnit *BPUnit = [HKUnit millimeterOfMercuryUnit];
    //透過這個HKUnit去建立單位 HKQuantity 
    HKQuantity *BPSystolicQuantity = [HKQuantity quantityWithUnit:BPUnit doubleValue:SIS];
    // 透過建立的單位與數值來建立這個單位類型(HKQuantityType)
    HKQuantityType *BPSystolicType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic];

[取得使用者權限]

  • 上面的方式僅僅是拿來作為處理資料欄位而已,接下來要開始去跟HealthKit查詢資料.在查詢資料之前,由於HealthKit上的資料都是儲存在手機上面,屬於個人私密資料.需要取得使用者的權限.
    //取出體重單位格式
    HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    //取出身高單位格式
    HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    // 將身高體重加入要求的權限集合,這裡有分"讀取"與"寫入"的集合
    NSSet *writeDataTypes = [NSSet setWithObjects:heightType, weightType, nil];
    NSSet *readDataTypes = [NSSet setWithObjects:heightType, weightType, nil];

    // 確認HealthKit 存不存在,這裡如果還是iPad 是不會有的,請注意.
    if ([HKHealthStore isHealthDataAvailable]) {        
        // 要求使用者同意
        [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {
            if (!success) {
                NSLog(@"You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@. If you're using a simulator, try it on a device.", error);
                
                return;
            }
            
            //處理成功以後,可能需要的資料讀取部分.
        }];
    }

[讀取資料]

  • 關於讀取資料這邊,需要注意的就是必須要取得正確的單位.
  • 還是一樣,讀到資料以後是async,所以可以用另外的thread來更新UI
  • 以下提供取得”心跳(Heart Rate)”的方式
    //心跳屬於複合資料欄位,需要用字串來找到HKUnit.文件不好找到.
    HKUnit *dataUnit = [HKUnit unitFromString:@"count/min"];
    
    //取得心跳的單位
    HKQuantity *HRQuantity = [HKQuantity quantityWithUnit:dataUnit doubleValue:heartRate];
    
    //取得心跳單位格式,注意HKQuantityTypeIdentifierHeartRate
    HKQuantityType *HeartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];

    //建立資料回傳的sort敘述    
    NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];

    //建立查詢的指令,注意因為我們只需要最近的所以把limit設定成1
    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:HeartRateType predicate:nil limit:1 sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
        if (!results) {
            //錯誤發生            
            return;
        }
        
        //取得心跳資料
        double usersHR = [mostRecentQuantity doubleValueForUnit:dataUnit];
    }];
    
    //執行查詢的指令
    [self.healthStore executeQuery:query];

[寫入資料]

  • 其實跟讀取一樣,主要也是要把HKUnit,HKQuantity與HKQuantityType搞定.
  • 這邊需要注意的是,儲存的資料都是有時間格式的.你必須要設定開始時間與結束時間.

    //建立心跳的單位
    HKUnit *dataUnit = [HKUnit unitFromString:@"count/min"];

    //建立心跳的數量單位
    HKQuantity *HRQuantity = [HKQuantity quantityWithUnit:dataUnit doubleValue:heartRate];

    //建立心跳的單位格式  
    HKQuantityType *HRType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
    NSDate *now = [NSDate date];

    //建立數量取樣
    HKQuantitySample *HRSample = [HKQuantitySample quantitySampleWithType:HRType                                                                          
                                                   quantity:HRQuantity                                                                         
                                                   startDate:now                                                                           
                                                   endDate:now];
    
    //存取該資料
    [self.healthStore saveObject:HRSample withCompletion:^(BOOL success, NSError *error) {
        if (!success) {
            NSLog(@"An error occured saving the sample %@. In your app, try to handle this gracefully. The error was: %@.", dataQuantityType, error);
            abort();
        }
        
        // 成功了之後,可以去更新資料.
        [self some_UI_update];
    }];

[iOS][Android][Python]工作上的一些雜事筆記20141212

前言:

本週都在Intel上課,大部份內容屬於NDA.只能找空閒時間看看其他的部分.

筆記:

  • [Mac OSX]一些常用的工具
    • 想要尋找Mac上面類似pietty一樣好用的軟體,卻忘記terminal 本身就有一樣的功能.更何況我有裝iTerm2
      • [指令] ssh -l username -p portnumber host
      • 參考:
    • 除了想要尋找類似pietty一樣的軟體外,也想要尋找可以一次完成SSH跟SFTP的軟體
      • Fugu 就是我想找的.
  • [Android][iOS] PhoneGap Beta Release
  • [Android] Android Studio 1.0 official release
  • [iOS] Parse支援Crash Log,可以考慮要不要加進去自己的App.不過我App用的是Parse 1.2.19現在已經到1.6了.
  • [IaaS][PaaS] 在Azure上面架設VM(Virtual Machine)很方便.但是對外的port要透過設定不然預設都是關閉的.這件事情讓我很困擾.
    • 問題:
      • 建立了伺服器與服務,但是對外都無法找到相對應的服務
      • 內部自己用curl或是其他client app可以找到相對應的服務
    • 解決方式:
      • 在Endpoint得加入你要開放給外面的port
      • 甚至可以做一個簡單的port 修改,比如說把xmpp 從5222改到80,裡面的80 Apache改到8080
    • 此外,現在Azure是有Preview的Manager Dashboard,東西有變多了.