安裝PPTPD及相關服務
夏天的午後,來杯下午茶,分享你我的心。
安裝PPTPD及相關服務
因為專案需求,需要把原本ASP的資料轉成JSON的格式
我知道ASP是大家動態網頁設計的好夥伴(笑)
(迷之音:ASP都出這麼久了,很多都已經轉成ASP.net了幹嘛這麼執著呢?)
就跟你說是專案需求了嘛(巴落去
這只是我的小小筆記,以免有機會又用上找不到怎麼做
尤其是程式語言對於陣列(Array)的操作方式都不大一樣
我盡量強化大家的JSON概念,盡量不特別提程式碼的部份
——————————–
學JSON格式只有二句話:
物件(object)用大括號 { }
陣列(array)用中括號 [ ]
先記住這概念
——————————–
ASP要使用JSON要下載此元件:
http://code.google.com/p/aspjson/
我們只需要他的ASP JSON (for production) 就好:
寫文的時候是JSON_2.0.4.asp
把他放在你的目錄然後用以下方式引用:
<!–#include file=”JSON_2.0.4.asp”–>
這裡有些範例蠻有用的:
http://code.google.com/p/aspjson/wiki/Samples2
引用部份範例來說明
物件寫法
<%
Dim o1
Set o1 = jsObject()
o1(“name”) = “Tom”
o1(“lastname”) = “Chen”
o1.Flush
%>
顯示
{“name”:”Tom”,”lastname”:”Chen”}
陣列寫法
<%
Dim o2
Set o2 = jsArray()
o2(Null) = 2
o2(Null) = 4
o2(Null) = 6
o2(Null) = 8
o2.Flush
%>
顯示
[2,4,6,8]
———————
所以我們學到,宣告空白變數使用Dim
決定是何種型態使用 Set 這個字
不要小看這個關鍵字,他可是很有用的
最後,當你把資料形態設定為jsObject之後
直接像範例一樣 o(“name”) 直接在括號之中放入新的key值,當成變數來指定
而資料形態設定為jsArray的時候
可以像範例一樣用o2(Null) 的方式增加值
範例集有提到jsArray和jsObject中的對轉,我覺得不是很重要,所以就不引用了
再來看比較tricky的
物件包物件
<%
Dim o3
Set o3 = jsObject()
Set o3(“person”) = jsObject()
o3(“person”)(“name”) = “Tom”
o3(“person”)(“lastname”) = “Chen”
Set o3(“equipment”) = jsObject()
o3(“equipment”)(“name”) = “keyboard”
o3(“equipment”)(“type”) = “electronic”
o3.Flush
%>
顯示
{“person”:{“name”:”Tom”,”lastname”:”Chen”},”equipment”:{“name”:”keyboard”,”type”:”electronic”}}
陣列包陣列
<%
Dim o4
Set o4 = jsArray()
Set o4(Null) = jsArray()
o4(Null)(Null) = 0
o4(Null)(Null) = 2
o4(Null)(Null) = 4
o4(Null)(Null) = 6
Set o4(Null) = jsArray()
o4(Null)(Null) = 1
o4(Null)(Null) = 3
o4(Null)(Null) = 5
o4(Null)(Null) = 7
o4.Flush
%>
顯示
[[0,2,4,6],[1,3,5,7]]
在陣列包陣列的範例中,就會明顯看到
其實程式它是從上到下,照順序執行
雖然 Set o4(Null) = jsArray() 這二行都一樣
但意義不同
難度慢慢增高摟
陣列包物件
<%
Dim o5
Set o5 = jsArray()
Set o5(Null) = jsObject()
o5(Null)(“name”) = “Tom”
o5(Null)(“lastname”) = “Chen”
Set o5(Null) = jsObject()
o5(Null)(“name”) = “Amy”
o5(Null)(“lastname”) = “Lin”
o5.Flush
%>
顯示
[{“name”:”Tom”,”lastname”:”Chen”},{“name”:”Amy”,”lastname”:”Lin”}]
這JSON格式已經接近資料庫撈出來的格式了
物件包陣列
<%
Dim o6
Set o6 = jsObject()
o6(“name”) = “Tom”
o6(“lastname”) = “Chen”
Set o6(“numbers”) = jsArray()
o6(“numbers”)(Null) = 2
o6(“numbers”)(Null) = 4
o6(“numbers”)(Null) = 5
o6(“numbers”)(Null) = 6
o6.Flush
%>
顯示
{“name”:”Tom”,”lastname”:”Chen”,”numbers”:[2,4,5,6]}
———————
最後跳過中間的步驟,直接開最後的大絕!
陣列包物件包陣列包物件
心理OS:哪那麼多陣列物件呀~
<%
Dim o7
Set o7 = jsArray()
Set o7(Null) = jsObject()
o7(Null)(“name”) = “Tom”
o7(Null)(“lastname”) = “Chen”
Set o7(Null)(“report”) = jsArray()
Set o7(Null)(“report”)(Null) = jsObject()
o7(Null)(“report”)(Null)(“subject”)=”Math”
o7(Null)(“report”)(Null)(“score”)=80
Set o7(Null)(“report”)(Null) = jsObject()
o7(Null)(“report”)(Null)(“subject”)=”English”
o7(Null)(“report”)(Null)(“score”)=90
Set o7(Null) = jsObject()
o7(Null)(“name”) = “Amy”
o7(Null)(“lastname”) = “Lin”
Set o7(Null)(“report”) = jsArray()
Set o7(Null)(“report”)(Null) = jsObject()
o7(Null)(“report”)(Null)(“subject”)=”Math”
o7(Null)(“report”)(Null)(“score”)=86
Set o7(Null)(“report”)(Null) = jsObject()
o7(Null)(“report”)(Null)(“subject”)=”English”
o7(Null)(“report”)(Null)(“score”)=88
o7.Flush
%>
顯示
[{“name”:”Tom”,”lastname”:”Chen”,”report”:[{“subject”:”Math”,”score”:80},{“subject”:”English”,”score”:90}]},{“name”:”Amy”,”lastname”:”Lin”,”report”:[{“subject”:”Math”,”score”:86},{“subject”:”English”,”score”:88}]}]
看起來很複雜其實並不然
換成XML的格式就長這樣
<data>
<student>
<name>Tom</name>
<lastname>Chen</lastname>
<report>
<subject>
<name>Math</name>
<score>80</score>
</subject>
<subject>
<name>English</name>
<score>90</score>
</subject>
</report>
</student>
<student>
<name>Amy</name>
<lastname>Lin</lastname>
<report>
<subject>
<name>Math</name>
<score>86</score>
</subject>
<subject>
<name>English</name>
<score>88</score>
</subject>
</report>
</student>
</data>
做成大家看得懂的表格
成績單1
姓名 | Tom Chen |
數學 | 80 |
英文 | 90 |
成績單2
姓名 | Amy Lin |
數學 | 86 |
英文 | 88 |
在回顧一下上面那二個很噁心的寫法
有困難嗎?有任何讓你造成不舒服的感覺嗎?
===============================================
以下內容看不懂就算了,沒關係
最後看看這資料庫的函式QueryToJSON
http://code.google.com/p/aspjson/wiki/SQLtoJSON
FunctionQueryToJSON(dbc, sql)
Dim rs, jsa, col
Set rs = dbc.Execute(sql)
Set jsa = jsArray()
WhileNot(rs.EOF Or rs.BOF)
Set jsa(Null)= jsObject()
ForEach col In rs.Fields
jsa(Null)(col.Name)= col.Value
Next
rs.MoveNext
Wend
SetQueryToJSON= jsa
EndFunction
如果上面都看懂的話,只是把欄位名稱和值,用For each印出來,放進jsObject裡而已
rs.Fields就是取得recordset的欄位物件,用
col.Name 取得欄位名
col.Value 取得值
若我資料庫有張表
student
s_id | name | lastname |
1 | Tom | Chen |
2 | Amy | Lin |
report
r_id | s_id | subject | score |
1 | 1 | Math | 80 |
2 | 1 | English | 90 |
3 | 2 | Math | 86 |
4 | 2 | English | 88 |
是不是我們的資料庫就可以這樣寫呢?
sql = “select * from student”
Set rs = dbc.Execute(sql)
Set jsa = jsArray()
While Not (rs.EOF Or rs.BOF)
Set jsa(Null) = jsObject()
For Each col In rs.Fields
jsa(Null)(col.Name) = col.Value
Next
sql2 = “SELECT subject,score FROM report WHERE s_id=”&rs(“s_id”)
Set rs2 = dbc.Execute(sql2)
Set jsa(Null)(“report”) = jsArray()
While Not (rs2.EOF Or rs2.BOF)
Set jsa(Null)(“report”)(Null) = jsObject()
For Each col2 In rs2.Fields
jsa(Null)(“report”)(Null)(col2.Name) = col2.Value
Next
rs2.MoveNext
Wend
rs.MoveNext
Wend
意興來潮來玩一下Windows Phone芒果機的開發
在開發環境的部分,除了有Windows 7
還要另外安裝Windows Phone SDK
Windows Phone SDK官網下載:
http://www.microsoft.com/zh-tw/download/details.aspx?id=27570
安裝之後,如果沒有Visual Studio 2010的話,他會很貼心的幫你安裝
Visual Studio 2010 Express供你使用
各位版大,不知道是否像我一樣
本身已經安裝好了Visual Studio 2010
在安裝之後仍然出現Express版,而本身完整版卻沒有安裝完成
可以遵循以下步驟:
相關樣版,而這問題可透過以下方式解決
要複製二個地方
第一個地方,C#版本的Silverlight for Windows Phone資料夾:
C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDEProjectTemplatesCSharpSilverlight for Windows Phone
整個Silverlight for Windows Phone資料夾複製到:
C:Users你的使用者名稱DocumentsVisual Studio 2010TemplatesProjectTemplatesVisual C#
第二個地方,VB版本的Silverlight for Windows Phone資料夾:
C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDEProjectTemplatesVisualBasicSilverlight for Windows Phone
整個Silverlight for Windows Phone資料夾複製到:
C:Users你的使用者名稱DocumentsVisual Studio 2010TemplatesProjectTemplatesVisual Basic
注意路徑中Visual Basic的空格,一個有一個沒有
若你的Win7版本是32位元的,把紅字中的(x86)字樣拿掉就是你的路徑
紅字的使用者名稱代換成你的使用者名稱
所以最後你的
C:Users你的使用者名稱DocumentsVisual Studio 2010TemplatesProjectTemplates
的 Visual Basic 和 Visual C# 資料夾都會有同名的但內容不一樣的 Silverlight for Windows Phone 資料夾
然後在開始選單中找到 所有程式 > Microsoft Visual Studio 2010 > Visual Studio Tools > Visual Studio 命令提示字元 (2010)
在指令鍵入
devenv.exe /setup
不做這個動作的話,在新增的頁面可以看到但不能建立
再重開VS2010即可
在檔案 > 新增 > 專案 之中
就會看到新的專案從你的VS2010出現摟
參考資料:
http://www.dotblogs.com.tw/ian/archive/2012/02/15/69380.aspx
小提示:這是比較進階的文章,不知道等一下的步驟在幹嘛的,就跳過整篇文章吧
———————————-
想必有用PHP & MySQL寫過網頁吧,想必phpMyAdmin應該是你的好朋友 (笑)
phpMyAdmin裡,其中有個還不錯用的功能就是Designer
可以畫資料庫的關聯圖,對於資料表關聯的了解有很大的幫助
但這功能在之後的版本,預設被關掉了
在這裡可以教你怎麼把它打開
———————————-
而PHP & MySQL自己重頭裝到好的很多
市面上整合平台更多
Appserv、XAMPP、WAMP、MAMP……
對於裝在不同的系統(Win、Mac、Linux),路徑也會不致相同
但是有個好消息
phpMyAdmin對於平台的相依性很小
只要PHP和MySQL的環境有架起來
phpMyAdmin它,都能跑
如果你夠大膽,可以去官網下載最新版phpMyAdmin
http://www.phpmyadmin.net/home_page/index.php
然後換上去 (撰文的時候使用phpMyAdmin 3.5.1版)
———————————-
以我在使用的XAMPP為例
Windows 版的路徑:
C:\xampp\phpMyAdmin
Mac 版的路徑:
/Applications/XAMPP/xamppfiles/phpmyadmin
Linux 版的路徑:
/opt/lampp/phpmyadmin
Apache先關掉,
然後將舊版的phpMyAdmin備份起來(目錄更名),將新版3.5.1的phpMyAdmin複製上去(不要用取代的)
———————————-
打開目錄底下的config.sample.inc.php,複製一份
檔名叫config.inc.php
使用文字編輯器打開
找到以下這一段:
/*
* phpMyAdmin configuration storage settings.
*/
/* User used to manipulate with storage */
// $cfg[‘Servers’][$i][‘controlhost’] = ”;
$cfg[‘Servers’][$i][‘controluser’] = ‘pma’;
$cfg[‘Servers’][$i][‘controlpass’] = ‘pmapass’;
/* Storage database and tables */
$cfg[‘Servers’][$i][‘pmadb’] = ‘phpmyadmin’;
$cfg[‘Servers’][$i][‘bookmarktable’] = ‘pma_bookmark’;
$cfg[‘Servers’][$i][‘relation’] = ‘pma_relation’;
$cfg[‘Servers’][$i][‘table_info’] = ‘pma_table_info’;
$cfg[‘Servers’][$i][‘table_coords’] = ‘pma_table_coords’;
$cfg[‘Servers’][$i][‘pdf_pages’] = ‘pma_pdf_pages’;
$cfg[‘Servers’][$i][‘column_info’] = ‘pma_column_info’;
$cfg[‘Servers’][$i][‘history’] = ‘pma_history’;
$cfg[‘Servers’][$i][‘table_uiprefs’] = ‘pma_table_uiprefs’;
$cfg[‘Servers’][$i][‘tracking’] = ‘pma_tracking’;
$cfg[‘Servers’][$i][‘designer_coords’] = ‘pma_designer_coords’;
$cfg[‘Servers’][$i][‘userconfig’] = ‘pma_userconfig’;
$cfg[‘Servers’][$i][‘recent’] = ‘pma_recent’;
$cfg[‘Servers’][$i][‘table_uiprefs’] = ‘pma_table_uiprefs’;
拿掉註解(不同版本,其中的值可能有多有少,會有些許不同,
找到你的那一段,不要直接複製,除非你很確定版本和我的相同),然後存檔
然後再打開Apache
———————————-
phpMyAdmin用MySQL的root帳號登入之後
點選匯入
檔案選擇 examples/create_tables.sql 的檔案,執行之後
會出現名字叫phpmyadmin的資料庫
然後按左上角的Exit鈕重新登入
就會選取資料庫時,就會看見Designer了
參考資料:
Enable Designer in PHPMyAdmin
http://www.novell.com/communities/node/8932/enable-designer-phpmyadmin
這是由之前寫的這一篇
http://j796160836.pixnet.net/blog/post/28994669
所延伸出來的
眼尖的網友已經發現,之前放上的程式碼範例已經不能Run了
把專案使用的Android版本放在2.3.3以下就可以正確執行
而把它升到4.0就會出錯
有人發現為什麼了嗎?
打開LogCat就可以清楚的看到
Android 4.0 (ICS)在網路的部份多了一個新的Exception
叫做android.os.NetworkOnMainThreadException
意思很白話的就是:網路的活動跑在主要執行緒上了啦!
ICS很貼心的告訴你,這樣子你的APP可能會因為等待回應太久(超過5秒)
而會被系統強制關閉(收到ANR)
(備註:之前是為了示例方便,所以沒有照多執行緒的寫法撰寫,在這裡當然也就不能執行啦
Android光這點就還蠻嚴謹的)
OK,瞭解為何出錯的原因
也剛好在這裡,帶大家看看多執行緒要怎麼改吧
專案的Layout版面等定義上和之前這篇一模一樣
有特別修改的地方會特別標出
package com.J_Test.httpPostTest;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class Main extends Activity implements OnClickListener
{
private EditText txtMessage;
private Button sendBtn;
private String uriAPI = "http://192.168.1.3/httptest/httpPostTest.php";
/* 「要更新版面」的訊息代碼 /
protected static final int REFRESH_DATA = 0x00000001;
/* 建立UI Thread使用的Handler,來接收其他Thread來的訊息 /
Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
// 顯示網路上抓取的資料
case REFRESH_DATA:
String result = null;
if (msg.obj instanceof String)
result = (String) msg.obj;
if (result != null)
// 印出網路回傳的文字
Toast.makeText(Main.this, result, Toast.LENGTH_LONG).show();
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtMessage = (EditText) findViewById(R.id.txt_message);
sendBtn = (Button) findViewById(R.id.send_btn);
if (sendBtn != null)
sendBtn.setOnClickListener(this);
}
@Override
public void onClick(View v)
{
if (v == sendBtn)
{
if (txtMessage != null)
{
// 擷取文字框上的文字
String msg = txtMessage.getEditableText().toString();
// 啟動一個Thread(執行緒),將要傳送的資料放進Runnable中,讓Thread執行
Thread t = new Thread(new sendPostRunnable(msg));
t.start();
}
}
}
private String sendPostDataToInternet(String strTxt)
{
/ 建立HTTP Post連線 /
HttpPost httpRequest = new HttpPost(uriAPI);
/*
* Post運作傳送變數必須用NameValuePair[]陣列儲存
*/
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("data", strTxt));
try
{
/ 發出HTTP request /
httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
/ 取得HTTP response /
HttpResponse httpResponse = new DefaultHttpClient()
.execute(httpRequest);
/ 若狀態碼為200 ok /
if (httpResponse.getStatusLine().getStatusCode() == 200)
{
/ 取出回應字串 /
String strResult = EntityUtils.toString(httpResponse
.getEntity());
// 回傳回應字串
return strResult;
}
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
class sendPostRunnable implements Runnable
{
String strTxt = null;
// 建構子,設定要傳的字串
public sendPostRunnable(String strTxt)
{
this.strTxt = strTxt;
}
@Override
public void run()
{
String result = sendPostDataToInternet(strTxt);
mHandler.obtainMessage(REFRESH_DATA, result).sendToTarget();
}
}
}
特別注意這裡
Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case REFRESH_DATA:
// …………(相關程式碼)
break;
}
}
};
這是Android對於多執行緒的寫法
這裡做了一個Handler來接收訊息
因為當你建立執行緒,資料處理與主執行緒無關
當然,新建出來的執行緒,是碰不到UI介面的 (會跳Exception)
所以才會如此設計
訊息,說穿了就是一個int,可以自行定義訊息的內容
/** 「要更新版面」的訊息代碼 */
protected static final intREFRESH_DATA = 0x00000001;
類別一開始就定義這個常數
然後在
public void handleMessage(Message msg){
}
的地方就可以使用 msg.what 存取到訊息的內容
這裡用Switch – case的方式撰寫
發訊息的函式如下
mHandler.obtainMessage(REFRESH_DATA, result).sendToTarget();
發訊息的相關方法呼叫可參考官方說明
http://developer.android.com/reference/android/os/Handler.html
文件上可看到,obtainMessage有這幾個多載方法
obtainMessage(int what);
obtainMessage(int what, int arg1, int arg2);
obtainMessage(int what, int arg1, int arg2, Object obj);
obtainMessage(int what, Object obj);
常用的有第一、第二、第四種
尤其是第四種,這訊息可以傳入Object
所以自由度很高
最後,是建立執行緒
// 啟動一個Thread(執行緒),將要傳送的資料放進Runnable中,讓Thread執行
Thread t = new Thread(new sendPostRunnable(msg));
t.start();
這裡是用一個臨時的執行緒的方式
在建構子之中傳入一個Runnable來達成
執行緒的部分也可以用匿名class的方式撰寫
// 擷取文字框上的文字
final String msg = txtMessage.getEditableText().toString();
new Thread()
{
public void run()
{
String result = sendPostDataToInternet(msg);
mHandler.obtainMessage(REFRESH_DATA, result).sendToTarget();
}
}.start();
但這樣的方式要注意,內部類別(Inner class)當中
只能存取外部的常數(這是Java的規定)
final String msg;
所以為何String前面要加上final了
詳細多執行緒可參考
[Android] 多執行緒-Handler和Thread的關係
http://j796160836.pixnet.net/blog/post/28766165
[Android] 關於Thread執行緒
http://j796160836.pixnet.net/blog/post/29895257
很多網友都問到,
為何我在Android傳送出來的資料
在瀏覽器中怎麼都看不見
因為資料到伺服器上沒有將它存下來
在這裡可以做一些修改
我們把傳到伺服器上的資料
用MySQL存下來,然後再顯示最後輸入的資料
以PHP為例,我們在phpmyadmin上
建立一個資料庫,名稱叫 httpPostTest
實際設定如圖:
這是其對應的SQL
CREATE TABLE IF NOT EXISTS weblog
(
log_id
int(11) NOT NULL AUTO_INCREMENT COMMENT ‘編號’,
data
varchar(255) NOT NULL COMMENT ‘傳入的資料’,
post_time
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘發佈時間’,
PRIMARY KEY (log_id
)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT=’訊息記錄’ AUTO_INCREMENT=1 ;
之前使用的 httpPostTest.php 我們做一些修改
<?php
// 資料庫相關資料
$database_dblink = "httpPostTest";
$username_dblink = "root";
$password_dblink = "YOUR_ROOT_PASSWORD";
// 建立資料庫連線
$dblink = mysql_pconnect("localhost", $username_dblink, $password_dblink) or trigger_error(mysql_error(),E_USER_ERROR);
mysql_query("SET NAMES utf8",$dblink);
mysql_query("SET CHARACTER_SET_CLIENT=utf8",$dblink);
mysql_query("SET CHARACTER_SET_RESULTS=utf8",$dblink);
mysql_select_db($database_dblink, $dblink);
// 宣告utf-8的編碼
header("Content-Type:text/html; charset=utf-8");
// 接收POST/GET的資料
$data=@$_REQUEST[‘data’];
// 如果有資料
if (strcmp(trim($data), "")!=0)
{
// 將資料輸入進資料庫
$insertSQL = sprintf("INSERT INTO weblog
(data
) VALUES (‘%s’);", $data);
mysql_query($insertSQL, $dblink) or die(mysql_error());
}
// 從資料庫撈出來最後一筆資料
$query_rs = "SELECT * FROM weblog
order by log_id desc limit 0,1";
$rs = mysql_query($query_rs, $dblink) or die(mysql_error());
$row = mysql_fetch_assoc($rs);
echo "data=".$row[‘data’]."n"."time=".$row[‘post_time’];
?>
這樣在瀏覽器就會暫存最後一筆的資料了
如果有學過PHP相關的語法
以上的程式碼應該不難才是
最後還是提醒一下,Android還沒有跑出來的朋友
若是在Logcat看到類似Permission denied的字眼
代表你忘記了AndroidManifest.xml的這句摟,詳細看之前寫的這篇吧
<!– 這裡加入可以存取網路的權限 –>
<uses-permission android:name="android.permission.INTERNET" />
關於source code的部份,我已經放上gitHub了
有關於iOS底下的Protocol
請參照至其版大的文章
Protocol in Objective-C
http://blog.eddie.com.tw/2010/12/11/protocol-in-objective-c/
這版大實在寫的思路很清晰,推薦一下摟
(看來我還是要多多拜讀別人的文章才是)
————————————————————————————————
為了響應不全文引用,以下採用節錄的,完整內容請移至版大的文章
Objective-C是單一繼承的,如果想要做到一個類別同時擁有多種型別的能力,可以透過實作其它型別的interface來達成這個目的。在Java/AS3是用”interface”這個關鍵字,在Objective-C則是用”@protocol”。
(有寫過Java/AS3的要特別注意不要把interface跟protocol搞混了
,在Objective-C的interface等於Java/AS3的class,而protocol則是相當於interface)
Johnny: 關於protocol這點,我也常常搞混…..= =||
如果你要新增一個自定的protocol的話,可以直接在你的專案裡新增一個protocol檔:
新增完成之後(它是一個header檔),就可以開始來寫了,
—————————————————————————————————
程式碼如下:
@protocol Drawable
@required
-(void) draw;
-(void) changeColor;
@optional
-(void) whateverMethod;
@end
在上面這段程式碼裡,我放了三個方法,但沒有寫內容。接下來如果我要實作自這個protocol的話,所有定義在@protocol裡的方法都得實作出來。
如果沒特別標明的,預設是@required。如果你要實作這個protocol的話,照英文字面來看,@required的部份是規定要實作的,@optional的話就隨你高興了。要注意的是@required跟@optional這兩個語法的影響範圍,是從它以下所有的method都會被影響,直到另一個directive或是@end為止
————————————————————————————————————————-
實作protocol的方法就是用”<>”標記,裡面放protocol的名稱。並不限定只能實作一個protocol,如果要實作多個protocol的話,則是用逗點分開
因為在protocol的地方已經有定義好了方法,所以在@interface的地方就不用再特別寫一次,只要在@implementation裡補上該實作的方法就行了。
// ————–
// interface
// ————–
#import <Cocoa/Cocoa.h>
#import “Drawable.h”
@interface Book : NSObject <Drawable>
{
int price;
}
@property int price;
@end
// ————–
// implementation
// ————–
#import “Book.h”
@implementation Book
@synthesize price;
// 實作方法draw
-(void) draw
{
NSLog(@”draw me!”);
}
// 實作方法changeColor
-(void) changeColor
{
NSLog(@”change color!”);
}
@end
————————————————————————————————————————-
Johnny: 簡單來講,protocol就是Java裡的介面(Interface),上面開出來的方法(method)
且有@required字樣的都要被實作(implementation)
protocol名稱加綴在類別(class)後面
只是為了要讓Complier,確實的去檢查,開出來的方法
是有都通通有實作完畢
實驗發現,某些Class對於protocol要求沒那麼嚴苛
只要實作出它要的方法,而不用加掛這個綴字
而且避免混淆,我現在習慣通通都加上去
(包含放在Class名稱之後的 < > ,和其protocol要的方法一起宣告在header檔)
我還是覺得還是要學Java一樣,嚴謹一點比較好,較不會出錯
在iOS開發上
若是從檔案讀取一些資料,想必會用到
這二個類別
Mutable是可變動的意思,所以建立之後還可以變動
NSMutableArray的話存取方式採用序號來存取值
而NSMutableDictionary採用自訂的鍵值(key)來存取值(value)
二者可以互相混用,NSMutableDictionary裡面有NSMutableArray
或是NSMutableArray裡面包含NSMutableDictionary (就像本次範例)
使用initWithContentsOfFile: 方法來載入plist
NSMutableArray要取得值使用objectAtIndex 方法
NSMutableDictionary要取得值使用objectForKey方法
提外話一下
如果有寫過php的話
他的概念和php的array有一點點類似
http://php.net/manual/en/language.types.array.php
而NSMutableArray類似於
<?php
$array = array("foo", "bar");
var_dump($array);
?>
array(4) { [0]=> string(3) “foo” [1]=> string(3) “bar” }
而NSMutableDictionary類似於
<?php
$array = array(
"foo" => "bar",
"bar" => "foo"
);
var_dump($array);
?>
array(4) { [“foo”]=> string(3) “bar” [“bar”]=> string(3) “foo” }
建立一個專案,在專案上按右鍵New File:
新增一個Property List,名叫article.plist
article.plist原始碼如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>title</key>
<string>title 01</string>
<key>content</key>
<string>content 01</string>
</dict>
<dict>
<key>title</key>
<string>title 02</string>
<key>content</key>
<string>content 02</string>
</dict>
<dict>
<key>title</key>
<string>title 03</string>
<key>content</key>
<string>content 03</string>
</dict>
</array>
</plist>
做一個Button出來,綁定TestpList_btn_onClick方法,該方法如下
– (IBAction)TestpList_btn_onClick:(id)sender {
// 取得專案中內建的pList路徑
NSString *path = [[NSBundlemainBundle] pathForResource:@"article"ofType:@"plist"];
NSLog(@"pList Path: %@n", path);
// 將pList中的資料從檔案載入
NSMutableArray *data_pList = [[NSMutableArrayalloc] initWithContentsOfFile:path];
for(NSInteger i=0;i<[data_pList count]; i++)
{
NSIndexPath *indexPath=[NSIndexPathindexPathForRow:i inSection:0];
NSString *title = [[data_pList objectAtIndex:indexPath.row] objectForKey:@"title"];
NSString *content = [[data_pList objectAtIndex:indexPath.row] objectForKey:@"content"];
NSLog(@"Index: %i Title: %@ Content: %@n", i, title, content);
}
}
然後運行程式,按下按鈕之後,在Log這邊得到以下結果:
順便補充在iOS上的printf裡的格式跟一般的C語言不同
string 要使用 %@
integer 要使用 %i 而不是 %d
這篇…我想就是給初次看JSON格式的人看的吧
如果懂了它的格式,不會太難
JSON全名叫做JavaScript Object Notation
就是在JavaScript之中,表示物件的一種格式
既然是格式,為何這麼多人愛用
可以好好瞭解一下
JSON格式簡單來說,就是這二句重點:
物件(object)用大括號 { }
陣列(array)用中括號 [ ]
先記住這概念
如果你看不懂JSON,可以用類似這種線上JSON格式化的網站
http://www.jsoneditoronline.org
幫助你瞭解
google搜尋一下:json format
就會有很多,這個網站我覺得做得不錯
我不是故意要打它的廣告,但這網站應該有助於JSON的學習
物件(object)
這裡說的object,不管你曾經在哪裡聽過這個名詞
他就是用key-value的方式儲存
來個範例吧!
{"subject":"Math","score":80}
這就是json裡的object
key-value就是指一個鍵值(key)對應一個值(value),跟變數很像
像是subject這個key有個值叫Math
score它的值為80
官方網站有個迷宮圖,有助於理解
陣列(array)
陣列可能就比較熟悉些
例如
[0,4,5,2,7,8,3]
不難理解,就像是之前寫陣列一類似
這裡的範例是使用數字,但也可以是文字、布林或者是陣列、物件、null。當然,混合就不用說了,絕對OK。
文字(text)的例子
["Tom", "John", "Amy", "Ivy"]
布林(Boolean)
[true, true, false, false, true, true]
硬要用key-value的方式解釋的話
就是0,1,2,3的照順序的數字
所以物件和陣列,某方面來說(不考慮資料損失),是可以互相轉換的
若 物件 -> 陣列
就會損失鍵值(key)的資料,留下值(value)
或是程式到時候指定說,要鍵值陣列(key array),就會把所有的鍵值(key)合併一起成陣列
若 陣列 -> 物件
就可以將每個值編上數字
這裡注意一點
json object的鍵值(key),一定要用文字做鍵值
以下是錯誤的
{0:"Tom", 1:"John", 2:"Amy", 3:"Ivy"} // error syntax
正確應改為
{"0":"Tom", "1":"John", "2":"Amy", "3":"Ivy"}
而整個JSON格式文件之中,是不能使用註解的
最後用這二個範例結束吧
成績單
[{"name":"Tom","lastname":"Chen","report":[{"subject":"Math","score":80},{"subject":"English","score":90}]},{"name":"Amy","lastname":"Lin","report":[{"subject":"Math","score":86},{"subject":"English","score":88}]}]
看起來很複雜,對吧?
其實不難
我們做成大家看得懂的表格
成績單1
姓名 | Tom Chen |
數學 | 80 |
英文 | 90 |
成績單2
姓名 | Amy Lin |
數學 | 86 |
英文 | 88 |
剛剛也有提到這是個成績單
一開始用一個陣列 [] 包起來,然後是二個物件 {}
[{ …學生1… },{ …學生2… }]
學生資料內有姓名和成績
{"name":"Tom","lastname":"Chen","report": …成績資料… }
成績的部份,因為有很多成績資料,所以有用陣列 [] 包起來
{"name":"Tom","lastname":"Chen","report":[{ …成績1… },{ …成績2… }]}
一個成績資料,也是個物件
{"subject":"Math","score":80}
全部拼起來就成那樣
如果用XML的格式寫就長這樣
<data>
<student>
<name>Tom</name>
<lastname>Chen</lastname>
<report>
<subject>
<name>Math</name>
<score>80</score>
</subject>
<subject>
<name>English</name>
<score>90</score>
</subject>
</report>
</student>
<student>
<name>Amy</name>
<lastname>Lin</lastname>
<report>
<subject>
<name>Math</name>
<score>86</score>
</subject>
<subject>
<name>English</name>
<score>88</score>
</subject>
</report>
</student>
</data>
應該不會太難
最後是網站上一開始附的範例
{"name":"John Smith","age":32,"employed":true,"address":{"street":"701 First Ave.","city":"Sunnyvale, CA 95125","country":"United States"},"children":[{"name":"Richard","age":7},{"name":"Susan","age":4},{"name":"James","age":3}]}
用XML可能會這麼寫:
<person>
<name>John Smith</name>
<age>32</age>
<employed>true</employed>
<address>
<street>701 First Ave.</street>
<city>Sunnyvale, CA 95125</city>
<country>United States</country>
</address>
<childrens>
<child>
<name>Richard</name>
<age>7</age>
</child>
<child>
<name>Susan</name>
<score>4</score>
</child>
<child>
<name>Susan</name>
<score>4</score>
</child>
</childrens>
</person>
比起XML,JSON的格式看起來是不是簡潔許多呢?
備註
在JSON的格式中,關於中文或其他非英文的部份
一定要用Unicode encode過
通常這個一般處理JSON的函式庫都會做掉
除非你自己print,自己兜出JSON格式
像是
我是中文 就會變成 u6211u662fu4e2du6587
類似這種 u開頭,接一串數字的東西
可以用這個工具做轉換(不過一般程式的library會做掉啦,這不用擔心)
http://www.htmlescape.net/stringescape_tool.html
另外有些字元在JSON不能直接打,需要做跳脫的(escape character) 在這
有些大家都很熟悉,就不細講了
"
\
/
b
f
n
r
t
這裡有些字碼表供參考
http://en.wikipedia.org/wiki/List_of_Unicode_characters
最後,練練英文,去JSON官方網站去看看吧
可以看到不同語言對於這個資料格式的實作
接下來也會提到實作的部分
參考資料:
這就是我們一直在用,不管是手機還是瀏覽器
在這虛擬化技術,雲端科技,Web 2.0等等蓬勃發展的年代
只要是上網,一定完全脫離不了Http的關係
對於網路,這是很基底的概念
想要讓技術層面更進一步
可以從日常接觸到的概念開始
讀通了,就很有用
—————————————————————–(以上都是廢話)—————————————————————
好吧,說真的我不大會教網路這種東西
可能有修過網路相關課程的人,可能會比較懂一點
我盡量從觀察到實際結果,配合網路概念解釋一遍
HTTP封包
我先放這次抓HTTP封包的截圖,再來解釋可能會比較有概念一點
這次所使用的軟體是Wireshark,是個抓封包的軟體
http://www.wireshark.org/download.html
裝好之後選擇網路介面然後就可以看到類似像上圖的東西了喔
我想你一定是在看我的文章,你看你的視窗上面有pixnet耶
講起網路,不免還是從OSI七層開始講起
這個部份我覺得wiki分類的真好 http://en.wikipedia.org/wiki/OSI_model
有興趣可以點開wiki的連結看,裡面有對應的文章
天音:這時候要像老師一樣諄諄教誨 (雖然我很不想~>"<)
OSI七層協定從下到上分別為
實體層(Physical Layer),資料鏈結層(Data Link Layer),網路層(Network Layer),傳輸層(Transport Layer),會談層(Session Layer),展現層(Presentation Layer),應用層(Application Layer)
裡面藍字的內容都是現有協定名字
wiki的目錄,一堆藍字都沒看過沒關係,在這裡,我們只要管 TCP HTTP 在哪一層就行了
對應到我們抓到的HTTP封包
第一行,是個概覽,這個封包總共收到幾個Frame(訊框)等等
第二行,就是我們收到的Frame(訊框),可以看到我們用Ethernet協定傳送,裡面記錄著最後傳和目標傳到的Mac位址….等等
第三行,就是TCP/IP中的IP協定(Internet Protocol),紀錄著來源和目標的IP等等資訊
第四行,Transmission Control Protocol縮寫就是TCP協定啦,HTTP連線也是基於TCP協定的,可以看到來源和目的的port(連接埠)號
第五行,就是HTTP協定(Hypertext Transfer Protocol)啦
這裡有展開,可以看到完整的HTTP標頭,一個HTTP連線原來附著這麼多的資訊,也是等下要講的重點
第六行,沒甚麼特別的,就只是網頁原始碼
封包和傳送原理
封包大概是這樣子的
從程式的眼光來看好了,軟體要送個資料到另一台電腦
除了 實體層(Physical Layer) 之外
會依序從上往下包
你可以想成要送人家禮物要包裝
或想成郵局要送郵務,要在包裹上貼很多標籤
或是辦公室的便利貼,貼一些備註訊息
每往下一層就加一些東西上去,到別人的電腦也是這樣,一層層拿掉標籤
最後得到資料
HTTP(應用層)也是如此,HTTP是基於TCP(傳輸層)的
在連線的時候也是如此
要先有TCP先連線才會可以跑HTTP的協定
不要問我為什麼要分那麼多層,網路這東西是有歷史的
很多東西到現今也還在變化 (但這個概念短時間已經是不會變了)
先解釋TCP
看到一堆紅線了嗎
分成前三組和後三組
前三組,就是出名的三向交握 (3-way handshake 也有人翻譯三次握手)
(天音:甚麼三向交握都看攏無)
看英文比中文意思比較準,意思就是 握手寒暄 啦
請設想一個情況,想你打skype給朋友
剛接起來網路電話的時候有沒有遇到這樣的情況
[SYN] 我: 哈嚕, 有沒有聽到聲音?
[SYN, ACK] A: 有聽到,那我呢?有沒有聽到聲音
[ACK] 我: 有滴~
(…….然後開始聊天,喔不是,是傳資料= =")
沒錯,三向交握就這麼簡單
標籤看起來很複雜而已
另外這組
[FIN, ACK]
[ACK]
是四向交握協定Four-way Handshake,用來關閉連線的
引用一下文章的內容
1. (B) –> ACK/FIN –> (A)
2. (B) <– ACK <– (A)
3. (B) <– ACK/FIN <– (A)
4. (B) –> ACK –> (A)
理當要有四個,為何只有二個?我想是Keep-Alive的關係
所以連線沒有斷,保持連線,若有其他的要求就可以馬上繼續連線
而不用重新建立連線
HTTP標頭
HTTP標頭裡面有很多資訊,像是Server的資訊,很明顯是跟Apache做連線
這裡也很清楚看到中間有Set-Coookie: 和PHPSESSID就是Session的ID啦
當Server使用Session時
雖然Session的資料是放在Server上沒錯〈Client看不到〉
為了分辨這個是那個Client連來的
所以會放一個Session ID給Client
(像是你去寄放物品的櫃台寄放東西,櫃台會交給你一把鑰匙一樣)
用鑰匙認顧客
而且這個Session ID會隨著你的連線,在下次要求的時候,放在標頭裡面
一起發送給Server
而在網頁設計當中,Session往往都被當成會員登入等依據
當你在清理Cookie的時候,Session ID也一起被你清掉了
也理所當然的被登出了
但Session使用上有些限制
他只能在同一個網域名字下使用,不能跨網域
Client端要開啟Cookie (當然這項,一般的瀏覽器通常都是開啟的)
通常Session和Cookie一樣,有Expires(失效時間)的
所以Facebook的認證上考慮到這些限制,才會採用OAuth 2.0
就是模擬Session的原理,只是把Session ID變成token的方式,用HTTP最簡單的GET方式
掛在網址串上面,以做身分的識別
(有關OAuth2.0相關的東西下次再講)
所以Hsuan網友在Android建立HTTP連線裡面
http://j796160836.pixnet.net/blog/post/28994669
問的問題:
我在1.php 寫 session
在2.php echo出session的值
這是沒問題的
但是如果用android端做測試的話
會抓不到session的值
請問這個跟android端有關係嗎??
所以在程式中,Session ID並沒有存下來
參考資料:
TCP: SYN ACK FIN RST PSH URG 詳解
https://sites.google.com/site/cimpleteam/articles/tcpsynackfinrstpshurgxiangjie
TCP/IP 概論
http://www2.meps.tp.edu.tw/documents/memo/TCP%EF%BC%8FIP%E6%A6%82%E8%AB%96/index.htm
最近在研究iOS開發,對於Http連線的好處
在這裡就不再贅述
之前寫過Android版本的,請見:
http://j796160836.pixnet.net/blog/post/28994669
雖然我也在學習中,我盡量解釋其方法
如果有誤,還煩請大大們指正
——————————————————————————————————————-
開一個新的專案
在Interface Builder版面設計中,拉出一個Button和一個Label
——————————————————————————————————————-
其中 Button 的 Touch Up Instide 中綁定 – (IBAction)request_btn_onclick:(id)sender 方法
Label 的 Referencing Outlets 綁定 @property (retain, nonatomic) IBOutletUILabel *label; 變數
——————————————————————————————————————-
在 ViewController.h 放入以下宣告
@interface ViewController : UIViewController
{
NSMutableData *responseData;
}
// 開始接收資料,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
// 接收新的資料時,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
// 下載完畢時,會呼叫此方法
– (void)connectionDidFinishLoading:(NSURLConnection *)connection;
// 連線錯誤時,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
——————————————————————————————————————-
在 ViewController.m 加入以下程式片段
#pragma mark – Connection delegate
– (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// 開始下載,重置responseData資料
NSLog(@”didReceiveResponse”);
[responseDatasetLength:0];
}
– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 下載中,附加資料
[responseDataappendData:data];
}
– (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 下載完成,釋放responseData
[connection release];
NSLog (@”succeeded %d byte received”, [responseDatalength]);
// 轉譯編碼文字
NSString *responseString = [[NSStringalloc] initWithData:responseDataencoding:NSUTF8StringEncoding];
[responseDatarelease];
label.text = responseString;
[responseString release];
}
– (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// 下載錯誤
label.text = [NSStringstringWithFormat:@”Connection failed: %@”,[error description]];
NSLog(@”Connection failed! Error – %@ %@”,
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
——————————————————————————————————————-
這段就是按鈕按下去會執行的語法
#pragma mark – Button onClick
– (IBAction)request_btn_onclick:(id)sender {
responseData = [[NSMutableDatadata] retain];
NSString *url = [NSString stringWithFormat:@”http://127.0.0.1/httptest/t.php”];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURLURLWithString:url ]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
——————————————————————————————————————-
我簡單解釋一下
剛剛在ViewController之中新增一個 NSMutableDatadata 變數 (Mutable代表可變動的)
然後在 – (IBAction)request_btn_onclick:(id)sender 這裡
指定一個 url 就是我們要瀏覽的位置,GET要上傳的內容就串在後面
再來建立一個 NSURLRequest 和 NSURLConnection 把連線建立起來
回應的部分傳進delegate (委派)之中
而delegate (委派)有四個
// 開始接收資料,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
當系統開始要接收資料的時候這個方法會被呼叫到
要把這 responseData 給清空,如果UI上有ProgressBar的話要將之歸零
// 接收新的資料時,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
每次資料在下載的時候,會不停的呼叫這個方法
可以看到這個data傳入的參數,就是每一小塊一小塊的資料
我們只要把它累加起來即可,如果UI上有ProgressBar的話就可以慢慢累加1
// 下載完畢時,會呼叫此方法
– (void)connectionDidFinishLoading:(NSURLConnection *)connection;
最後跑完會呼叫這個方法,就是你需要做處理的部分
例如顯示到畫面上,存入SQLite….等等
// 連線錯誤時,會呼叫此方法
– (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
最後就是這個,中間若有網路錯誤等因素就會呼叫這個方法
你可以跳一個提示框或是印Log
這個範例的url是指到本機的Apache Server的其中的一隻php網頁
你也可以換成yahoo等網站,只是會跑出一堆網頁原始碼而已
可以玩看看
——————————————————————————————————————-
以下是我不負責任的把語法翻成大家熟悉的Java
對於像我一樣,對Objective-C有閱讀障礙的
可以看一下(當然,底下的程式完全不能跑,就不用複製了….XD)
public class ViewController implements NSURLConnectionDelegate {
public static UILabel label;
private NSMutableData responseData;
public void viewDidLoad() {
responseData = new NSMutableData();
NSString url = “http://127.0.0.1/httptest/t.php”;
NSURLRequest request = new NSURLRequest(url);
new NSURLConnection(request, this);
}
@Override
public void didReceiveResponse(NSURLConnection connection, NSURLResponse response) {
// 開始下載,重置responseData資料
NSLog(“didReceiveResponse”);
responseData.setLength(0);
}
@Override
public void didReceiveData(NSURLConnection connection, NSData data) {
// 下載中,附加資料
responseData.appendData(data);
}
@Override
public void connectionDidFinishLoading(NSURLConnection connection) {
// 下載完成,釋放responseData
connection = null;
NSLog(NSString.format(“succeeded %d byte received”, responseData.length));
// 轉譯編碼文字
NSString responseNSString = responseData.toNSStringWithEncoding(NSUTF8NSStringEncoding);
responseData = null;
label.text = responseNSString;
responseNSString = null;
}
@Override
public void didFailWithError(NSURLConnection connection, NSError error) {
// 下載錯誤
label.text = NSString.format(“Connection failed: %s”, error.description());
NSLog(NSString.format(“Connection failed! Error – %s”,
error.localizedDescription()));
}
}
——————————————————————————————————————-
參考資料
http://www.01-labor.com/2011/07/nsurlconnectionhttp.html
http://stm237.iteye.com/blog/1005752
NSURLConnection官方文件
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html