您的位置:首页 > 移动开发 > IOS开发

【IOS】IOS开发问题解决方法索引(三)

2015-05-15 09:30 429 查看

1 判断js对象是否拥有某属性

/article/4664161.html

两种方式,但稍有区别

1,in运算符

1

2

3

var
obj = {name:'jack'};


alert('name'
in
obj); // --> true


alert('toString'
in
obj); // --> true


可看到无论是name,还是原形链上的toString,都能检测到返回true。

2,hasOwnProperty方法

1

2

3

var
obj = {name:'jack'};


obj.hasOwnProperty('name'); // --> true


obj.hasOwnProperty('toString'); // --> false


原型链上继承过来的属性无法通过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的交互

/article/4667197.html

iOS UIWebView中javascript与Objective-C交互、获取摄像头

/article/5108273.html

IOS开发之——objective-c与javascript交互

http://blog.sina.com.cn/s/blog_50e0bce501018ydu.html

若是传入参数是字符串,记得加上单引号‘’

3 编写自文档化的代码

编写自文档化的代码

/article/4687338.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 关于文件操作 获取 文件大小

/article/11751202.html

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编码

/article/1553702.html

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)介绍和使用

/article/1389854.html

GCD的使用方法

http://beauty-soft.net/blog/ceiba/object-c/20130513/639.html

GCD之dispatchqueue

/article/5939343.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文档

/article/1389145.html

【iOS开发】GDataXML使用实例

http://blog.csdn.net/qbins/article/details/12043813

15 objective-c选择器Selector

IOS SEL (@selector) 原理及使用总结(一)

/article/7588949.html

【IOS】Object-C 中的Selector 概念

http://blog.sina.com.cn/s/blog_735065f90100yopd.html

16 IOS中延时执行的几种方式

iOS延时执行的几种方法

/article/10058780.html

IOS中延时执行的几种方式的比较和汇总

http://bluevt.org/?p=128

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,故一旦完成初始化,其数组大小就已经确定了,数组长度不再可变。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: