1 判斷js對象是否擁有某屬性
http://www.cnblogs.com/snandy/archive/2011/03/04/1970162.html
兩種方式,但稍有區別
1,in運算符
1 2 3 |
|
可看到無論是name,還是原形鏈上的toString,都能檢測到返回true。
2,hasOwnProperty方法
1 2 3 |
|
原型鏈上繼承過來的屬性無法通過hasOwnProperty檢測到,返回false。
需注意的是,雖然in能檢測到原型鏈的屬性,但for in通常卻不行。
當然重寫原型後for in在IE9/Firefox/Safari/Chrome/Opera下是可見的。見:for in的缺陷
2 objective-c與js交互
※用 Objective-C 取得與設定 JavaScript 對象
要從 Objective-C取得網頁中的 JavaScript 對象,也就是對 windowScriptObject做一些 KVC 調用,像是 valueForKey: 與 valueForKeyPath:。如果我們在 JS 裏頭,想要知道目前的網頁位置,會這麼寫:
var location = window.location.href;
用 Objective-C 就可以這麼調用:
NSString *location = [[webView windowScriptObject]valueForKeyPath:@"location.href"];
如果我們要設定 window.location.href,要求開啓另外一個網頁,在JS 裏頭:
window.location.href = 'http://spring-studio.net';
在Objective-C:
[[webView windowScriptObject]setValue:@"http://spring-studio.net"forKeyPath:@"location.href"];
由於Objective-C 與 JS 本身的語言特性不同,在兩種語言之間相互傳遞東西之間,就可以看到兩者的差別:
· JS 雖然是 OO,但是並沒有 class,所以將 JS 對象傳到 Obj C 程序裏頭,除了基本字串會轉換成 NSString、基本數字會轉成 NSNumber,像是 Array 等其他對象,在 Objective-C 中,都是 WebScriptObject 這個 Class。意思就是,JS 的 Array 不會幫你轉換成 NSArray。
· 從 JS 裏頭傳一個空對象給 Objective-C 程序,用的不是 Objective-C 裏頭原本表示「沒有東西」的方式,像是 NULL、nil、NSNull 等,而是專屬 WebKit 使用的 WebUndefined。
所以,如果我們想要看一個 JS Array 裏頭有什麼東西,就要先取得這個對象裏頭叫做 length 的 value,然後用webScriptValueAtIndex: 去看在該 index 位置的內容。
假如我們在 JS 裏頭這樣寫:
var JSArray ={'zonble', 'dot', 'net'};
for (var i= 0; i < JSArray.length; i++) {
console.log(JSArray[i]);
}
在Objective-C 裏頭就會變成這樣:
WebScriptObject*obj = (WebScriptObject *)JSArray;
NSUInteger count= [[obj valueForKey:@"length"] integerValue];
NSMutableArray *a= [NSMutableArray array];
for (NSUInteger i= 0; i < count; i++) {
NSString *item= [obj webScriptValueAtIndex:i];
NSLog(@"item:%@",item);
}
※用 ObjectiveC 調用 JavaScriptfunction
要用 Objective-C 調用網頁中的 JS function,大概有幾種方法。第一種是直接寫一段跟你在網頁中會撰寫的 JS 一模一樣的程序,叫 windowScriptObject用 evaluateWebScript: 執行。
例如,我們想要在網頁中產生一個新的 JS function,內容是:
function x(x){
return x+ 1;
}
所以在 Objective-C 中可以這樣寫;
[[webViewwindowScriptObject] evaluateWebScript:@"function x(x) { return x +1;}"];
接下來我們就可以調用 window.x():
NSNumber *result= [[webView windowScriptObject] evaluateWebScript:@"x(1)"];
NSLog(@"result:%d",[result integerValue]); // Returns 2
由於在 JS 中,每個 funciton 其實都是對象,所以我們還可以直接取得 window.x 叫這個對象執行自己。
在 JS 裏頭如果這樣寫:
window.x.call(window.x,1);
Objective-C 中便是這樣:
WebScriptObject *x= [[webView windowScriptObject] valueForKey:@"x"];
NSNumber *result= [x callWebScriptMethod:@"call"withArguments:[NSArray arrayWithObjects:x,[NSNumbernumberWithInt:1], nil]];
這種讓某個 WebScriptObject 自己執行自己的寫法,其實比較不會用於從 Objective-C 調用 JS 這一端,而是接下來會提到的,由JS 調用 Objective-C,因爲這樣 JS 就可以把一個 callback function 送到 Objective-C 程序裏頭。
如果我們在做網頁,我們只想要更新網頁中的一個區塊,就會利用 AJAX 的技巧,只對這個區塊需要的資料,對server 發出 request,並且在 request 完成的時候,要求執行一段callback function,更新這一個區塊的顯示內容。從 JS 調用 Objective-C也可以做類似的事情,如果 Objective-C程序裏頭需要一定時間的運算,或是我們可能是在 Objective-C 裏頭抓取網路資料,我們便可以把一個 callback function 送到 Objective-C程序裏,要求Objective-C程序在做完工作後,執行這段 callback function。
※ DOM
WebKit 裏頭,所有的 DOM 對象都繼承自 DOMObject,DOMObject 又繼承自 WebScriptObject,所以我們在取得了某個 DOM 對象之後,也可以從 Objective-C 程序中,要求這個 DOM 對象執行 JS 程序。
假如我們的網頁中,有一個 id 叫做 “#s” 的文字輸入框(text input),而我們希望現在鍵盤輸入的焦點放在這個輸入框上,在 JS 裏頭會這樣寫:
document.querySelector('#s').focus();
在Objective-C中寫法:
DOMDocument*document = [[webView mainFrame] DOMDocument];
[[documentquerySelector:@"#s"]callWebScriptMethod:@"focus"withArguments:nil];
※用 JavaScript 存取 ObjectiveC 的 Value
要讓網頁中的 JS 程序可以調用 Objective-C 對象,方法是把某個 Objective-C 對象註冊成 JS 中 window 對象的屬性。之後,JS 便也可以調用這個對象的 method,也可以取得這個對象的各種Value,只要是 KVC 可以取得的 Value,像是 NSString、NSNumber、NSDate、NSArray、NSDictionary、NSValue…等。JS 傳 Array 到 Objective-C 時,還需要特別做些處理才能變成 NSArray,從 Obj C 傳一個 NSArray 到 JS 時,會自動變成 JS Array。
首先我們要注意的是將 Objective-C 對象註冊給 window 對象的時機,由於每次重新載入網頁,window 對象的內容都會有所變動-畢竟每個網頁都會有不同的 JS 程序,所以,我們需要在適當的時機做這件事情。我們首先要指定 WebView 的 frame loading delegate(用 setFrameLoadDelegate:),並且實作 webView:didClearWindowObject:forFrame:,WebView 只要更新了 windowScriptObject,就會調用這一段程序。
假如我們現在要讓網頁中的 JS 可以使用目前的 controller 對象,會這樣寫:
-(void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject*)windowObject forFrame:(WebFrame *)frame
{
[windowObjectsetValue:self forKey:@"controller"];
}
如此一來,只要調用 window.controller,就可以調用我們的 Objective-C 對象。假如我們的 Objective-C Class 裏頭有這些成員變數:
@interface MyController: NSObject
{
IBOutlet WebView*webView;
IBOUtlet NSWindow *window;
NSString *stringValue;
NSInteger numberValue;
NSArray *arrayValue;
NSDate *dateValue;
NSDictionary *dictValue;
NSRect frameValue;
}
@end
指定一下 Value:
stringValue= @"string";
numberValue = 24;
arrayValue =[[NSArray arrayWithObjects:@"text",[NSNumbernumberWithInt:30], nil] retain];
dateValue =[[NSDate date] retain];
dictValue =[[NSDictionary dictionaryWithObjectsAndKeys:@"value1",@"key1", @"value2", @"key2", @"value3", @"key3", nil]retain];
frameValue =[window frame];
用 JS 讀讀看:
var c =window.controller;
var main =document.getElementByIdx_x('main');
var HTML= '';
if (c) {
HTML+= '
' + c.stringValue + '
';
HTML+= '
' + c.numberValue + '
';
HTML+= '
' + c.arrayValue + '
';
HTML+= '
' + c.dateValue + '
';
HTML+= '
' + c.dictValue + '
';
HTML+= '
' + c.frameValue + '
';
main.innerHTML= HTML;
}
結果如下:
string 24 text,302010-09-09 00:01:04 +0800 { key1 = value1; key2 = value2; key3 = value3; }NSRect: {{275, 72}, {570, 657}}
不過,如果你看完上面的範例,就直接照做,應該不會直接成功出現正確的結果,而是會拿到一堆 undefined,原因是,Objective-C 對象的 Value 預設被保護起來,不會讓 JS 直接存取。要讓 JS 可以存取 Objective-C 對象的 Value,需要操作+isKeyExcludedFromWebScript: 針對傳入的 Key 一一處理,如果我們希望 JS 可以存取這個 key,就回傳 NO:
+(BOOL)isKeyExcludedFromWebScript:(const char *)name
{
if (!strcmp(name, "stringValue")){
return NO;
}
return YES;
}
除了可以讀取 Objective-C對象的 Value 外,也可以設定 Value,相當於在 Objective-C中使用 setValue:forKey:,如果在上面的 JS 程序中,我們想要修改 stringValue,直接調用 c.stringValue = ‘new value’ 即可。像前面提到,在這裡傳給 Objective-C的 JS 對象,除了字串與數字外,class都是 WebScriptObject,空對象是 WebUndefined。
※ 用 JavaScript 調用 ObjectiveC method
Objective-C 的語法沿襲自 SmallTalk,Objective-C 的 selector,與 JS 的 function 語法有相當的差異。WebKit 預設的實事是,如果我們要在JS 調用 Objective-C selector,就是把所有的參數往後面擺,並且把所有的冒號改成底線,而原來 selector 如果有底線的話,又要另外處理。
假使我們的 controller 對象有個 method,在 Objective-C 中寫成這樣:
- (void)setA:(id)ab:(id)b c:(id)c;
在 JS 中就這麼調用:
controller.setA_b_c_('a', 'b', 'c');
實在有點醜。所以 WebKit 提供一個方法,可以讓我們把某個 Objective-C selector 變成好看一點的 JS function。我們要實作 webScriptNameForSelector:
+(NSString *)webScriptNameForSelector:(SEL)selector
{
if (selector== @selector(setA:b:c:)) {
return @"setABC";
}
return nil;
}
以後就可以這麼調用:
controller.setABC('a', 'b', 'c');
我們同樣可以決定哪些 selector 可以給 JS 使用,哪些要保護起來,方法是實作isSelectorExcludedFromWebScript:。而我們可以改變某個 Objective-C selector 在 JS 中的名稱,我們也可以改變某個 value 的 key,方法是實作 webScriptNameForKey:。
有幾件事情需要注意一下:
用 JavaScript 調用 Objective C 2.0 的 property
在上面,我們用 JS 調用 window.controller.stringValue,與設定裏頭的 value 時,這邊很像我們使用 Objective-C 2.0 的語法,但其實做的是不一樣的事情。用 JS 調用 controller.stringValue,對應到的 Objective-C 語法是 [controller valueForKey:@"stringValue"],而不是調用 Objective-C 對象的 property。
如果我們的 Objective-C 對象有個 property 叫做 stringValue,我們知道,Objective-C property 其實會在編譯時,變成 getter/setter method,在 JS 裏頭,我們便應該要調用controller.stringValue() 與 controller.setStringValue_()。
Javascript 中,Function 即對象的特性
JS 的 function 是對象,當一個 Objective-C 對象的 method 出現在 JS 中時,這個 method 在 JS 中,也可以或多或少當做對象處理。我們在上面產生了 setABC,也可以試試看把它倒出來瞧瞧:
console.log(controller.setABC);
我們可以從結果看到:
function setABC() {[native code] }
這個 function 是 native code。因爲是 native code,所以我們無法對這個 function 調用 call 或是 apply。
另外,在把我們的 Objective-C 對象註冊成 window.controller 後,我們會許也會想要讓 controller 變成一個 function 來執行,像是調用window.controller();或是,我們就只想要產生一個可以讓 JS 調用的 function,而不是整個對象都放進 JS 裏頭。我們只要在 Objective-C 對象中,實作invokeDefaultMethodWithArguments:,就可以回傳在調用window.controller() 時想要的結果。
現在我們可以綜合練習一下。前面提到,由於我們可以把 JS 對象以 WebScriptObject 這個 class 傳入 Obj C 程序,Objective-C 程序中也可以要求執行 WebScriptObject 的各項 function。我們假如想把 A 與 B 兩個數字丟進 Objective-C 程序裏頭做個加法,加完之後出現在網頁上,於是我們寫了一個 Objective-C method:
-(void)numberWithA:(id)a plusB:(id)b callback:(id)callback
{
NSInteger result= [a integerValue] + [b integerValue];
[callbackcallWebScriptMethod:@"call" withArguments:[NSArrayarrayWithObjects:callback,[NSNumber numberWithInteger:result],nil]];
}
JS 裏頭就可以這樣調用:
window.controller.numberWithA_plusB_callback_(1,2,function(result) {
var main= document.getElementByIdx_x('main');
main.innerText= result;
});
※ 其他平臺上 WebKit 的用法
除了 Mac OS X,WebKit 這幾年也慢慢移植到其他的作業系統與framework 中,也或多或少都有 Native API 要求 WebView 執行 Js,以及從 JS 調用 Native API 的機制。
跟 Mac OS X 比較起來,IOS 上 UIWebView 的公開 API 實在少上許多。想要讓 UIWebView 執行一段 JS,可以透過調用stringByEvaluatingJavaScriptFromString:,只會回傳字串結果,所以能夠做到的事情也就變得有限,通常大概就拿來取得像 window.title 這些資訊。在 IOS 上我們沒辦法將某個 Objective-C 對象變成 JS 對象,所以,在網頁中觸發了某些事件,想要通知 Objective-C 這一端,往往會選擇使用像「zonble://」這類 Customized URL scheme。
ChromeOS 完全以 WebKit 製作使用者介面,不過我們沒辦法在 ChomeOS 上寫我們在這邊所討論的桌面或行動應用程序,所以不在我們討論之列。(順道岔題,ChromeOS 是設計來給 Netbook 使用的作業系統,可是像 Toshiba 都已經用 Android,做出比 Netbook 更小的 Smartbook,而且應用程序更多,ChromeOS 的產品做出來的話,實在很像Google 拿出兩套東西,自己跟自己對打)。
Android 的 WebView 對象提供一個叫做 addJavascriptInterface() 的 method,可以將某個 Java 對象註冊成 JS 的 window 對象的某個屬性,就可以讓 JS 調用 Java 對象。不過,在調用 Java 對象時,只能夠傳遞簡單的文字、數字,複雜的 JS 對象就沒辦法了。而在 Android 上想要 WebView 執行一段 JS,在文件中沒看到相關資料,網路上面找到的說法是,可以透過 loadUrl(),把某段 JS 用 bookmarklet 的形式傳進去。
在 QtWebKit
裏頭,可以對 QWebFrame
調用addToJavaScriptWindowObject,把某個 QObject
暴露在 JS
環境中,我不清楚 JS
可以傳遞哪些東西到 QObject
裏頭就是了。在 QtWebKit
中也可以取得網頁裏頭的 DOM
對象(QWebElement
、QWebElementCollection),我們可以對 QWebFrame
還有這些 DOM
對象調用 evaluateJavaScript,執行 Javascript。
GTK 方面,因爲是 C API,所以在應用程序與 JS 之間,就不是透過操作包裝好的對象,而是調用 WebKit 裏頭 JavaScript Engine 的 C API。
※ JavaScriptCore Framework
我們在 Mac OS X 上面,也可以透過 C API,要求 WebView 執行 Javascript。首先要 import 。如果我們想要簡單改一下window.location.href:
JSGlobalContextRefglobalContext = [[webView mainFrame] globalContext];
JSValueRefexception = NULL;
JSStringRef script=JSStringCreateWithUTF8CString("window.location.href='http://spring-studio.net'");
JSEvaluateScript(globalContext,script, NULL, NULL, 0, &exception);
JSStringRelease(script);
如果我們想要讓 WebView 裏頭的 JS,可以調用我們的 C Function:
-(void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject*)windowObject forFrame:(WebFrame *)frame
{
JSGlobalContextRefglobalContext = [frame globalContext];
JSStringRefname = JSStringCreateWithUTF8CString("myFunc");
JSObjectRefobj = JSObjectMakeFunctionWithCallback(globalContext, name,(JSObjectCallAsFunctionCallback)myFunc);
JSObjectSetProperty(globalContext, [windowObject JSObject], name, obj, 0, NULL);
JSStringRelease(name);
}
那麼,只要 JS 調用 window.myFunc(),就可以取得們放在 myFunc 這個 C function 中回傳的結果:
JSValueRefmyFunc(JSContextRef ctx, JSObjectRef function, JSObjectRefthisObject, size_t argumentCount, const JSValueRefarguments[], JSValueRef* exception)
{
return JSValueMakeNumber(ctx,42);
}
iOS開發之Objective-C與JavaScript的交互
http://www.cnblogs.com/zhuqil/archive/2011/08/03/2126562.html
iOS UIWebView中javascript與Objective-C交互、獲取攝像頭
http://www.cnblogs.com/lwme/p/ios-call-objc-camera-from-javascript-in-uiwebview.html
IOS開發之——objective-c與javascript交互
http://blog.sina.com.cn/s/blog_50e0bce501018ydu.html
若是傳入參數是字符串,記得加上單引號‘’
3 編寫自文檔化的代碼
編寫自文檔化的代碼
http://www.cnblogs.com/anderslly/archive/2009/06/21/write-self-documenting-code.html
編寫自文檔化的代碼
http://kb.cnblogs.com/page/47707/
4 objective-c與js交互
如何在Objective-C的類裏面聲明私有方法.
http://hi.baidu.com/shiqyn/item/52887ff19d3df61aa729885f
Objective-C中的類本身並沒有私有方法這個概念,聲明在 .h 文件中的方法都是公有的。不過,要想實現私有方法的效果還是有辦法的,就是用Category。
// Hello.h
#import<Cocoa/Cocoa.h>
@interface Hello: NSObject {
//變量聲明
}
// 方法聲明
@end
//
// Hello.m
#import"Hello.h"
@interfaceHello () //=>此處Hello命名一致,後邊跟括號
//=>@property(某種) aType ivarName ; 可實現私有變量
// 私有方法聲明
- (void)test;
@end
@implementationHello
// 私有方法實現
//=>@synthesizeivarName; 有私有變量的話
- (void)test {
// ..
}
// 方法實現
@end
在上面這個例子中,test 就是 Hello 類的“私有方法”了。再次證明,Category這個東東真的很強大~
5 iphone中的delegate委託機制
Objective-C回調機制(delegate,protocol)
http://blog.sina.com.cn/s/blog_6545eb460100pyjy.html
iphone中的delegate委託機制
http://wsqwsq000.iteye.com/blog/1121155
詳解Objective-C中委託和協議
http://mobile.51cto.com/iphone-283416.htm
6 iOS delegate使用時注意
delegate方法調用前,最好先判斷是否可以回調:
if([_testDelegaterespondsToSelector:@selector(onResult:)])
{
[_testDelegateonResult:str];
}
7 ios 關於文件操作 獲取 文件大小
ios 關於文件操作 獲取 文件大小
http://blog.csdn.net/xlxying/article/details/8047695
c語言 實現
#include "sys/stat.h"
- (long long) fileSizeAtPath:(NSString*) filePath{
struct statst;
if(lstat([filePathcStringUsingEncoding:NSUTF8StringEncoding], &st) == 0){
returnst.st_size;
}
return 0;
}
objective-c 語言實現
-(long long) fileSizeAtPath:(NSString*) filePath{
NSFileManager*manager = [NSFileManager defaultManager];
if ([managerfileExistsAtPath:filePath]){
return [[managerattributesOfItemAtPath:filePath error:nil] fileSize];
}
return 0;
}
如果將兩種方法循環1000次,我們就可以發現兩者之間巨大的性能差距了,在我的測試環境中,結果如下,c函數的耗時僅是第一種方法的5%,在此推薦 c語言
一個空的文件夾 其中獲取大小爲68k ,應該是系統文件吧。
8 objective-c中NSString默認編碼格式不是utf-8
iOS NSString 轉換爲UTF-8編碼
http://blog.csdn.net/u011872945/article/details/11771651
9 Audio Queue開發——退出程序時要關閉音頻通道
使用Audio Queue Service進行音頻操作時,使用了AudioQueueNewOutput方法,來開闢一個Audio Queue輸出到硬件的通道,開啓後,在程序退出前,一定要用AudioQueueDispose方法釋放通道(而且最好是設置爲YES,即立即釋放),不然程序無法再次啓動該通道,除非IOS重啓。
10 AudioQueue開發——Buffer緩存設置
AudioQueue開發時,需要用到一個緩衝池隊列,該隊列的預讀取只需要一次就行了,不需要放在play方法中,只需放在初始化方法中就行。
11 objective-csetter方法調用時機
在保存類成員的數據時,需要使用self.***的操作來調用setter方法,才能最終保存數據。
12 對象nil狀態的使用
若一個對象需要重複使用,即alloc 後會release,那麼在release後,最好將其置爲nil,才能利用是否等於nil來判斷對象狀態。
13 IOS多線程—— GCD使用
使用GCD
http://blog.devtang.com/blog/2012/02/22/use-gcd/
iOS多線程編程之GrandCentral Dispatch(GCD)介紹和使用
http://blog.csdn.net/totogo2010/article/details/8016129
GCD的使用方法
http://beauty-soft.net/blog/ceiba/object-c/20130513/639.html
GCD之dispatchqueue
http://www.cnblogs.com/scorpiozj/archive/2011/07/25/2116459.html
GCD介紹(一): 基本概念和Dispatch Queue
http://www.dreamingwish.com/dream-2012/gcd介紹(一)-基本概念和dispatch-queue.html
14 IOS——GDataXML使用
如何在項目中設置使用GDataXML解析類庫
http://www.cnblogs.com/lovecode/articles/2305416.html
IOS學習筆記27—使用GDataXML解析XML文檔
http://blog.csdn.net/ryantang03/article/details/7868246
【iOS開發】GDataXML使用實例
http://blog.csdn.net/qbins/article/details/12043813
15 objective-c選擇器Selector
IOS SEL (@selector) 原理及使用總結(一)
http://blog.csdn.net/fengsh998/article/details/8612969
【IOS】Object-C 中的Selector 概念
http://blog.sina.com.cn/s/blog_735065f90100yopd.html
16 IOS中延時執行的幾種方式
iOS延時執行的幾種方法
http://blog.csdn.net/czcty/article/details/7730089
IOS中延時執行的幾種方式的比較和彙總
17 Xcode工程中添加js文件,需要添加到copy Bundle Resources
18 OC中^符號使用
用^符號支持將一個代碼段以參數形式添加到方法中;
19 IOS內存管理
Autorelease只能用於屬性,不能用於內部成員變量,因爲內部成員變量賦值時不會有retain方法來增加引用計數。
對於引用計數:
Self.屬性 = 時,會增加一次引用計數。若是self.test = [[NSString alloc] init];最終引用計數是2,而不是1
所以正確的聲明方式是:
_test =[[NSString alloc] init];
或者self.test =[[[NSString alloc] init] autorelease];
20 UIImageView不支持多組圖片載入播放
使用UIImageView播放幾組圖片以實現動畫效果時,同一個UIImageView對象實例無法切換載入多組圖片。
究其原因:是因爲UIImageView的AnimationImage屬性是一個NSArray類型,而不是NSMutableArray,故一旦完成初始化,其數組大小就已經確定了,數組長度不再可變。