Fork me on GitHub

Programming Design Notes

Objective-C 將 JSON 轉為 Object

| Comments

JSON 是現時流行的資料格式,與 XML 相比,JSON 更為輕巧。在傳輸相同資料時,JSON 在大部份情況也會較 XML 的檔案小,在手機網路上傳輸 JSON 亦會比 XML 快。

iPhone Cocoa Touch Framework 中並沒有 Library 去操作 JSON 資料格式。幸好有一些人為 Objective C 製作了能夠操作 JSON 資料格式的 Library

而我使用的是這一款: json-framework

下載完成後將整個 JSON 資料夾複製到 Project 內,然後那一個 Class 要使用到 JSON Library 只要引入 JSON.h 就可以了。

#import "JSON.h"

使用方法非常簡單,看看以下例子。

JSON 資料 (轉自: http://www.json.org/example.html):
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

以上的資料我會放到一個 data.json 的檔案內。

現在讀取這個檔案:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
NSString *jsonStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];


SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *json = [parser objectWithString:jsonStr error:nil];

NSDictionary *glossary = [json objectForKey:@"glossary"];
NSString *glossaryTitle = [glossary objectForKey:@"title"];

NSDictionary *glossDiv = [glossary objectForKey:@"GlossDiv"];
NSString *glossDivTitle = [glossDiv objectForKey:@"title"];

NSArray *glossSeeAlso = [[[[glossDiv objectForKey:@"GlossList"]
objectForKey: @"GlossEntry"]
objectForKey: @"GlossDef"]
objectForKey: @"GlossSeeAlso"];

NSLog(@"Glossary Title: %@", glossaryTitle);
NSLog(@"GlossDiv Title : %@", glossDivTitle);

NSLog(@"GlossSeeAlso item 1: %@", [glossSeeAlso objectAtIndex:0]);
NSLog(@"GlossSeeAlso item 2: %@", [glossSeeAlso objectAtIndex:1]);

第 2 行是將檔案內容放到 NSString 內。

第 5 行創造一個 JSON Parser,準備將 JSON 字串轉換成 Object

第 6 行將 JSON 字串轉換成 NSDictionary,而這一個 NSDictionary 內的 Object 亦已經被 JSON Parser 轉換成相對應的 Object,例如: NSArray, NSDictionary, NSString 等等。

第 8 行是使用關鍵字 “glossary” 抽取 Object,因為這個 Object 是包含以下部份的資料:
{
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}

第 9 行是使用以上的資料再加上關鍵字 “title” 去抽取內容,以上資料加上關鍵字 “title” 內的內容是 “example glossary”,所以回傳的 Object 是一個 NSString Object

第 14 行則是抽取 “GlossSeeAlso” 的內容,以內容則是以下這些:
["GML", "XML"]

如你所見,這是一個 Array, 所以回傳的 Object 是一個 NSArray Object

最後打印出來的內容會是以下這些:
2010-08-27 15:15:44.003 JSON[47655:207] Glossary Title: example glossary
2010-08-27 15:15:44.049 JSON[47655:207] GlossDiv Title : S
2010-08-27 15:15:44.050 JSON[47655:207] GlossSeeAlso item 1: GML
2010-08-27 15:15:44.050 JSON[47655:207] GlossSeeAlso item 2: XML

如果 JSON 資料是經由網路去讀取,可以用以下方法:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pro.ctlok.com/data.json"]];

NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

NSString *jsonStr = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];

範例下載: JSON.zip

從 Objective-C 轉到 Swift 可看看這篇: From Objective-C to Learning Swift


相關書籍: Beginning iPhone and iPad Development with iOS4: Exploring the iPhone SDKiPhone SDK 4 Advanced Programming: Advanced Application Development for Apple iPhone and iPod touchBeginning iPhone SDK Programming with Objective-C (Wrox Programmer to Programmer)

在 JSP 使用 Expression Language 拿取 Spring Bean 內容

| Comments

有好一陣沒有更新這個部落格了,這數星期也在製作一個個人項目,忙得沒時間打文章,現在這個項目的主要功能也完成了,可遲一點再更新。

有使用 Spring Framework 的也知道 Spring bean 在不同的 bean 內也輕易存取得到,方法亦有幾種。

例如使用 Java Annotation 的方式去自動注入
@Autowired
private MyBean bean;

又可以使用 XML 的方式去注入
<bean id="person" class="org.springframework.beans.TestBean" scope="prototype">
<property name="age" value="10"/>
<property name="spouse">
<bean class="org.springframework.beans.TestBean">
<property name="age" value="11"/>
</bean>
</property>
</bean>

又可以在執行階段動態取得 Spring bean
ApplicationContext context =  WebApplicationContextUtils.getWebApplicationContext(getServletContext());
Object bean = context.getBean("myBean");

那在 JSP 中怎麼取得 Spring bean,你可以使用第三種方式去取得 bean,但我不喜歡在 JSP 中插入 Java 程式碼,所以我會使用以下方法。

在設定 Spring web mvcviewResolver 時加入一個參數就可以了:




就是這樣簡單,你就可以在 JSP 用以下方式拿到 bean 的內容:
<c:out value="${ bean.value }" />

除了這個方法外,你亦可以幾 Spring bean 放到 HttpServletRequest 內,令 JSP 可以存取得到,但沒有以上方法簡單直接。

相關書籍: Spring Recipes: A Problem-Solution ApproachSpring in ActionSpring Recipes: A Problem-Solution Approach, Second Edition

動態地取得 WEB-INF 的位置

| Comments

動態地取得 WEB-INF 的位置:

public class MyClassName {

private static final String WEBINF = "WEB-INF";

public String getWebInfPath() {

String filePath = "";

URL url = MyClassName.class.getResource("MyClassName.class");
String className = url.getFile();

filePath = className.substring(0, className.indexOf(WEBINF)
+ WEBINF.length());
return filePath;
}

}

轉自: http://www.melandri.net/2009/05/28/get-the-web-inf-folder-path/

相關書籍: Beginning Java&trade; EE 6 Platform with GlassFish&trade; 3: From Novice to ProfessionalThe Java EE 6 Tutorial: Basic Concepts (4th Edition) (Java Series)Real World Java EE Patterns Rethinking Best Practices

Objective-C - NSString 和 NSDate 互相轉換

| Comments

記錄一下在 Objective-CNSString 轉換為 NSDateNSDate 轉換為 NSString 的方法。

很簡單,使用 NSDateFormatter 就可以令 NSStringNSDate 互相轉換。

NSDate 轉換為 NSString:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString *strDate = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"%@", strDate);
[dateFormatter release];

結果:
2010-08-04 16:01:03

NSString 轉換為 NSDate:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:@"2010-08-04 16:01:03"];
NSLog(@"%@", date);
[dateFormatter release];

結果:
2010-08-04 16:01:03 +0800

從 Objective-C 轉到 Swift 可看看這篇: From Objective-C to Learning Swift


相關書籍: Programming in Objective-C 2.0 (2nd Edition)Learn Objective&ndash;C on the Mac (Learn Series)Programming in Objective-C

iPhone - UIAlertView 的使用方法

| Comments

UIAlertView 這個元件並不常用,如果將 UIAlertView 用作顯示普通訊息,這不是一個好的介面設計,因為彈出來的訊息是非常引人注意的,就好像 Javascriptalert 一樣,彈出來後整個視窗也不能操作,一定要用戶按下 “OK” 才能繼續操作,我相信各位也不喜歡到經常彈出 alert box 的網站吧,在 iPhone 也是同樣道理。

那何時才使用 UIAlertView? 應該是有某些訊息無論如何也要用戶去知道,不是那些無關緊要的事,有可能是你的應用程式發生一些問題,令操作不能繼續的訊息。例如你的應用程式必須依賴網路來拿取資料,但用戶的裝置根本沒有連接網路,這時候你便需要使用 UIAlertView 去提示用戶去連接網路,不然應用程式不能運作。

首先是最簡單,只顯示訊息並只有一個 “OK” 按鈕的 Message Box:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message 1......\nMessage 2......" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

[alert show];
[alert release];

樣子:

因為按下 “OK” 按鈕後不需要任何動作,所以也不用設置代理 (delegate)。

cancelButtonTitleUIAlertView 預設的按鈕,是必須設備的,但按鈕顯示的文字則可以任意更改。

otherButtonTitles 則可以用來增加按鈕,每加入一個 NSString 就會多一個按鈕。好像以下這樣:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message 1......\nMessage 2......" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:@"Button 1", @"Button 2", @"Button 3", nil];

這樣便會增加多三個按鈕,加上 Cancel Button 一共有 4 個按鈕。

樣子:

如果想按下按鈕後有其他動作,你需要在相對應的 Class 加上 UIAlertViewDelegateprotocol

例如我想 UIViewControllerUIAlertView 的代理:
ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIAlertViewDelegate> {

}

@end

ViewController.m 加上以下方法:
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//Code.....
}

UIAlertViewCancelButtonbuttonIndex 是 0,其他按鈕的 buttonIndex 則順序增加。

可以這樣判斷用戶究竟按下了那一個按鈕:
- (void)loadView {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"Message 1......\nMessage 2......" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Button 1", @"Button 2", @"Button 3", nil];

[alert show];
[alert release];

}

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{

switch (buttonIndex) {
case 0:
NSLog(@"Cancel Button Pressed");
break;
case 1:
NSLog(@"Button 1 Pressed");
break;
case 2:
NSLog(@"Button 2 Pressed");
break;
case 3:
NSLog(@"Button 3 Pressed");
break;
default:
break;
}

}

從 Objective-C 轉到 Swift 可看看這篇: From Objective-C to Learning Swift


相關書籍: Iphone SDK 4 Advanced Programming--Advanced Development for Apple Iphone & iPod TouchBeginning iPhone and iPad Development with SDK 4: Exploring the iPhone SDKiPhone SDK Programming, A Beginner's Guide