分类目录归档:iOS

在Unity Android 程序中使用动态库及注意事项

很多C/C++代码以动态库的方式供第三方调用,在Unity中,这类文件(dll for windows, *.so file for Android/Linux, *.dylib for MAC OSX)叫插件。

在Unity开发的Android程序中使用动态库插件是非常方便的,曾经因为被误导而放弃使用unity,转而研究Android通过原生Java的JNI方式包装*.so文件,虽然还行,但是JNI晦涩丑陋的API实在看着不舒服。相对而言,C#也是可以直接包装*.so文件并在Android系统中直接调用的,而且Unity制作Android app跟Unity制作其他平台的app是无缝的,只是在发布时选择要发布的平台就行了,真正做到了平台无关,极大的方便了开发。

我还没仔细研究如何在Android Studio中开发NDK,这里只介绍如何用Eclipse开发NDK。

在Eclipse中开发NDK的几个必须的安装项:NDK编译环境、Android SDK直接从官网单独下载单独安装;CDT、ADT插件可以直接从Eclipse的help的插件管理中安装。

然后就可以创建项目了:

1、打开Eclipse,通过File->New Project,弹出对话框,填入项目名称:

01

2、点Next,出现Config Project窗口:

02

由于只用于编译NDK,所以把前两项的钩钩去掉,第三个勾上,标记为so项目;目录也自定义一下,因为通常情况下我只会为编译so文件配置项目,真正的代码会单独放在更顶层的目录,方便跨平台的其他编译项目使用。结果如下:

03

4、按Finish结束创建过程,目录结构如下:

04

5、添加Native代码支持。也就是JNI相关的东西:在左侧项目根目录上右键->Android Tools->Add Native Support…

05

在随后弹出的对话框中输入要生成的so文件的名字:

06

这时候会发现多了一个目录:

07

6、编译配置

在jni目录中加入Application.mk文件和Android.mk文件

Application.mk:

APP_ABI      := all
#APP_ABI       := armeabi-v7a
#APP_ABI       += armeabi

#APP_OPTIM        := release
APP_PLATFORM     := android-8
#APP_BUILD_SCRIPT := Android.mk

# GNU STL implements most C++11 features. Use either gnustl_static or gnustl_shared
# Without this your C++ code will not be able to access headers like <thread>, <mutex>
#APP_STL := stlport_static
#APP_CPPFLAGS := -std=c++11 -frtti -fexceptions 
APP_STL       := gnustl_static
APP_CPPFLAGS  := -std=gnu++11 -pthread -frtti -fexceptions -DNDEBUG #-NDEBUG -mfpu=neon -fomit-frame-pointer -DULM_BLOCKED -msse3 -mfpmath=sse

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := PNLib
LOCAL_SRC_FILES := PNLib.cpp

include $(BUILD_SHARED_LIBRARY)

本来Android.mk文件很简单,把所有头文件、cpp文件加入,直接编译就行。但是对于我的项目这远远不够,因为我的代码要跨平台,有各个平台的编译项目单独出去,同时使用一份src文件,所以代码被放到了顶层目录中的src目录下,我需要遍历这个目录并把它加入NDK编译系统中来,所以下面从网上找了一段遍历头文件和cpp文件的脚本来用了:

# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE   := PNLib

# 锟斤拷锟斤拷锟皆硷拷锟斤拷源锟侥硷拷目录锟斤拷源锟侥硷拷锟斤拷缀锟斤拷
MY_FILES_PATH  :=  $(LOCAL_PATH)/../../src

#$(warning $(MY_FILES_PATH))

MY_FILES_SUFFIX := %.cpp %.c

# 递归遍历目录下的所有的文件
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

# 获取相应的源文件
MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) ) 
MY_ALL_FILES := $(MY_ALL_FILES:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%)
MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES)) 
MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)

# 去除字串的重复单词
define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
  ${seen}
endef

# 递归遍历获取所有目录
MY_ALL_DIRS := $(dir $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*/) ) )
MY_ALL_DIRS := $(call uniq,$(MY_ALL_DIRS))

# 赋值给NDK编译系统
LOCAL_SRC_FILES  := $(MY_SRC_LIST)
LOCAL_C_INCLUDES := $(MY_ALL_DIRS)

# Add additional include directories
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../Eigen-3.2.2   
#必须从Android.mk配置文件中拿掉对Eigen的直接包含,放到程序代码中用相对路径包含:
# #include "../../Eigen-3.2.2/Eigen"
# using namespace Eigen;

#$(warning $(LOCAL_SRC_FILES))
#$(warning $(LOCAL_C_INCLUDES))

# use log system in NDK
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

7、最后一步是为此项目配置一个NDK编译工具:

A、项目->右键->Properties,弹出项目属性对话框:

08

B、选中Builders,点击New按钮,弹出框中选中“Program”,点击OK:

09

C、出现新Builder配置对话框,随便起个名字“New_Builder_for_NDK”;

在Main标签页中,“Location”项,通过“Browse File System…“找到NDK的build文件,windows系统为ndk-build.cmd,Mac或其他类Linux系统为ndk-build;

工作目录”Working Directory“指定当前项目下的jni目录就行了。

10

D、切到Refresh页,勾选”Refresh resources upon completion“

11

E、切到”Build Options“页,勾选”Specify working set of relevant resources“,点击后面按钮”Specify Resources…“,指本项目下的jni目录。

12

最后的编译条如下:

13

点击左边锤子图标即可对项目进行编译。剩下的工作就是一步步修正跨平台代码,最后生成PNLib.so文件。

 

以上步骤有几个地方需要特别注意:

1、使用gun++11

NKD支持c++11,GCC已经支持大部分c++11特性,所以可以直接使用gun++11。实际上,如果用c++11,Android版程序可能报错:DLLNotFundException,编译出来的动态库在Android系统中无法加载,所以Application.mk文件中必须如下配置:

APP_STL       := gnustl_static
APP_CPPFLAGS  := -std=gnu++11 -pthread -frtti -fexceptions -DNDEBUG

2、x64版ndk目前还有bug

你的系统即便是x64的,也别下载x64版本的ndk,否则会报找不到make.exe的问题(make.exe不是内部命令XXXXXXXXX)

 

3、不识别vector、list等模板类的问题

Add

APP_STL := stlport_static

to their Application.mk file.

其实Android插件应该用APP_STL := gnustl_static

 

4、使用第三方库Eigen导致array等冲突的问题

原因是在NDK的Android.mk文件中把Eigen的路径也加入到里面了。

正确的做法是,不在Android.mk文件加入Eigen,而是在程序代码中直接包含Eigen头文件。

 

Image not found when using dylib in xcode

Some errors like this:

dyld: Library not loaded: /usr/local/lib/libXXX.dylib
Referenced from: /sers/david/Projekte/Test/build/Debug/Test.app/Contents/MacOS/Test
Reason: image not found

 

Answer:

Make sure to install the command line tools from developer.apple.com and then add the library in your project . Run the following script in your Xcode :Targets->Build Phases->Run Script and just execute :
install_name_tool -id @executable_path/../Frameworks/librayName.dylib “$SRCROOT/librayName.dylib”
——itechnician

 

Important information:

Before going for solution, you should know what is new with dependent library “dylib” in MAC as compare to dependent library “dll” in windows.

The major difference in dylib vs dll is “install name“. The install name is a path baked into the dynamic library that says where to find the library at runtime. It does not matter where you copy your dylibs, It will always point to old path(except without changing install name). You can know original search path(install name) by using command as below

otool -L a.dylib

(just drag dylib in place of a.dylib)

For more detail about install name, refer the link : http://www.chilkatforum.com/questions/4235/how-to-distribute-a-dylib-with-a-mac-os-x-application

Now, solution for changing the new location for dylib(“install name”) is just use install_name_tool as below

install_name_tool -change old path of dylb new path of dylib

you can get old path by otool -L command described above already.(old path i.e. original path)

“install_name_tool -change” can change search path of dylib and executable as well.

You can use this in Xcode by writing in “Run script” file in your project.

——NIlesh Srivastava

Address:

http://stackoverflow.com/questions/4876740/xcode-keeps-searching-dylib-at-wrong-path

 

================================================

In fact, there are 8 steps to deal with this issue:

1. Drag your custom dylib file to project

2. Click “+” at top of “Build Phases” page to add a “Copy Files” segment

3. Select “Framework” at destination line

4. Click “+” at the bottom of copy files segment to add your dylib

5. Click “+” at top of “Build Phases” page to add a “Run Script” segment

6. Past bellow line in shell box:

install_name_tool -id @executable_path/../Frameworks/libraryName.dylib “$SRCROOT/libraryName.dylib”

7. Change “libraryName.dylib” to your library name

8. Build.

屏幕快照 2014-12-25 下午2.12.25

Good luck! :)

 

在iOS设备上运行python

作者: 张初阳

iOS上其实有很多优秀的跨平台项目,比如RubyMotion,能作出一些简单的UI逻辑了。

最近因为分析数据的缘故需要用python,昨天突然想在iOS上跑python,毕竟有的时候iPad还是挺好的。可是老婆的iPad没有越狱,而且被我升级了iOS6,所以不能通过shell来运行。

网上搜索了下有Python for iOS,应该很不错,可是有些贵,于是想想自己能不能也写一个?

应该可以吧。

其实很久之前就有了在iOS上假设更高级语言的IDE的想法,毕竟iOS就是一个BSD。设备有了Cydia之后拥有更多的权限和更多的API,甚至底层的调用,自由度会很大。至于Cydia的延伸行为我就不发表意见了。

我记得首先在iOS上出现的IDE是关于html5的,这个很好理解,有webkit对吧。

言归正传,我使用的是boost的lib,然后加上python到c的翻译,原理很简单。

这是一个简单的测试:

b_large_xwiw_7cc400000a611262

主要的工作就是编译boost到ios上面,我已经把boost和python-c两个文件价上传到了baidu网盘。

链接地址在下面,只要直接加入工程就好了。网上还有一种方法是做成动态链接库,链接地址在下面,过程老长老长了- -不过是一个一劳永逸的方法,我提供的文件每个工程都需要添加,而且比较大。

boost:http://pan.baidu.com/share/link?shareid=68742&uk=1194307691

python-c:http://pan.baidu.com/share/link?shareid=68743&uk=1194307691

另外给点福利,iOS的越狱入门书,别理解错了,是教你怎么自己动手不用工具越狱ios设备并获得高级权限,也就是ios黑客的入门教材。

连接在下面:

http://pan.baidu.com/share/link?shareid=68809&uk=1194307691

其实开发不难,重在参与。

Xcode 快捷键

0.跳到指定行command + L;

1.配置高亮方案:Fonts & Colors

2.键盘快捷键:Key Bindings

3.代码缩进:Re-indent selection。(快捷键CTRL+I)

4.代码自动完成:Table(代码上屏),Esc(打开自动完成列表)

5.command+[  (代码左移),花+] (代码右移)

6.双击某个“括号匹配”的某个分隔符(如 {  } ( ) [ ] 等),Xcode会选中它以及与它匹配的括号之间的全部代码。

7.快速重命名局部变量名(右键-Edit All In Scope)command+control+E

8.重构(右键-Reflector…)

9.常用光标控制按键:(也适用与TextEdit,Safari URL地址栏等文本域)上 下 左 右 箭头     control-A:移动到行首(同command+左箭头) control-E:移动到行尾(End,同command+右箭头)control-K:删除(Kill)光标所在行中光标后的代码,便于你重写行尾的代码。

10.切换到头文件或源码文件:command + option + 上箭头,可以在头文件与源码文件之间快速切换。菜单为View – Switch Head/Source File。或者单击代码导航条的最后一个控件。

11.书签:添加书签(command – D,跟浏览器里的添加书签快捷键一样),可以在项目Groups&Files下的Bookmarks下看到添加的书签

12.command+shift+E:显示/隐藏代码屏幕上面的浏览器窗格

13.代码折叠:单击左边的灰色竖线即可。(View-Code Folding)

14.代码功能注释:

// MARK:  ***(标签,功能同#pragma mark ***),
// TODO: ***
// FIXME: ***
// !!!: ***
// ???: ***

15.Control-2: 快速浏览当前文件的成员列表

16.帮助:快速帮助(option+单击),文档搜索(option+双击)

17.修改Xcode代码自动完成的左花括号单独成行(if语句的下一行):

运行Terminal,输入

defaults write com.apple.Xcode XCCodeSenseFormattingOptions -dict BlockSeparator “n”
后重启Xcode即应用。

18  command +  /      快速注释或取消注释

[转]iOS中NSUserDefaults的用法(轻量级本地数据存储)

NSUserDefaults适合存储轻量级的本地数据,比如要保存一个登陆界面的数据,用户名、密码之类的,个人觉得使用NSUserDefaults是首选。下次再登陆的时候就可以直接从NSUserDefaults里面读取上次登陆的信息咯。

因为如果使用自己建立的plist文件什么的,还得自己显示创建文件,读取文件,很麻烦,而是用NSUserDefaults则不用管这些东西,就像读字符串一样,直接读取就可以了。

NSUserDefaults支持的数据格式有:NSNumber(Integer、Float、Double),NSString,NSDate,NSArray,NSDictionary,BOOL类型。很实用吧

NSUserDefaults很方便,读取也很容易。下面给出一个示例看看如何使用:(PS:更详细的也可以参考官方文档哈)

ViewController.h文件中主要是放几个控件,用于显示存储的数据:

  1. #import <UIKit/UIKit.h>
  2. @interface ViewController : UIViewController
  3. {
  4.     IBOutlet UILabel *txtInteger;
  5.     IBOutlet UILabel *txtFloat;
  6.     IBOutlet UILabel *txtDouble;
  7.     IBOutlet UILabel *txtNSString;
  8.     IBOutlet UILabel *txtNSDate;
  9.     IBOutlet UILabel *txtNSArray;
  10.     IBOutlet UILabel *txtNSDictionary;
  11. }
  12. @end

ViewController.m文件中最重要的是两个方法:saveNSUserDefaults:用于将各种类型数据保存到NSUserDefaults中

readNSUserDefautls:用于从NSUserDefaults中读取各种类型的数据。在viewDidLoad中调用这两个方法就可以看出结果咯

  1. #import “ViewController.h”
  2. @interface ViewController ()
  3. @end
  4. @implementation ViewController
  5. – (void)viewDidLoad
  6. {
  7.     [super viewDidLoad];
  8.     [self saveNSUserDefaults];  //调用此方法将各种数据存储到NSUserDefautls中,在下面定义
  9.     [self readNSUserDefaults];  //调用此方法从NSUserDefautls中读取各种数据,在下面定义
  10. }
  11. – (void)viewDidUnload
  12. {
  13.     [txtNSString release];
  14.     txtNSString = nil;
  15.     [txtNSDate release];
  16.     txtNSDate = nil;
  17.     [txtNSArray release];
  18.     txtNSArray = nil;
  19.     [txtNSDictionary release];
  20.     txtNSDictionary = nil;
  21.     [txtInteger release];
  22.     txtInteger = nil;
  23.     [txtFloat release];
  24.     txtFloat = nil;
  25.     [txtDouble release];
  26.     txtDouble = nil;
  27.     [super viewDidUnload];
  28.     // Release any retained subviews of the main view.
  29. }
  30. – (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  31. {
  32.     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
  33. }
  34. – (void)dealloc {
  35.     [txtNSString release];
  36.     [txtNSDate release];
  37.     [txtNSArray release];
  38.     [txtNSDictionary release];
  39.     [txtInteger release];
  40.     [txtFloat release];
  41.     [txtDouble release];
  42.     [super dealloc];
  43. }
  44. //保存数据到NSUserDefaults
  45. -(void)saveNSUserDefaults
  46. {
  47.     NSString *myString = @”enuola”;
  48.     int myInteger = 100;
  49.     float myFloat = 50.0f;
  50.     double myDouble = 20.0;
  51.     NSDate *myDate = [NSDate date];
  52.     NSArray *myArray = [NSArray arrayWithObjects:@”hello”, @”world”, nil];
  53.     NSDictionary *myDictionary = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@”enuo”, @”20″, nil] forKeys:[NSArray arrayWithObjects:@”name”, @”age”, nil]];
  54.     //将上述数据全部存储到NSUserDefaults中
  55.     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  56.     //存储时,除NSNumber类型使用对应的类型意外,其他的都是使用setObject:forKey:
  57.     [userDefaults setInteger:myInteger forKey:@”myInteger”];
  58.     [userDefaults setFloat:myFloat forKey:@”myFloat”];
  59.     [userDefaults setDouble:myDouble forKey:@”myDouble”];
  60.     [userDefaults setObject:myString forKey:@”myString”];
  61.     [userDefaults setObject:myDate forKey:@”myDate”];
  62.     [userDefaults setObject:myArray forKey:@”myArray”];
  63.     [userDefaults setObject:myDictionary forKey:@”myDictionary”];
  64.     //这里建议同步存储到磁盘中,但是不是必须的
  65.     [userDefaults synchronize];
  66. }
  67. //从NSUserDefaults中读取数据
  68. -(void)readNSUserDefaults
  69. {
  70.     NSUserDefaults *userDefaultes = [NSUserDefaults standardUserDefaults];
  71.     //读取数据到各个label中
  72.     //读取整型int类型的数据
  73.     NSInteger myInteger = [userDefaultes integerForKey:@”myInteger”];
  74.     txtInteger.text = [NSString stringWithFormat:@”%d”,myInteger];
  75.     //读取浮点型float类型的数据
  76.     float myFloat = [userDefaultes floatForKey:@”myFloat”];
  77.     txtFloat.text = [NSString stringWithFormat:@”%f”,myFloat];
  78.     //读取double类型的数据
  79.     double myDouble = [userDefaultes doubleForKey:@”myDouble”];
  80.     txtDouble.text = [NSString stringWithFormat:@”%f”,myDouble];
  81.     //读取NSString类型的数据
  82.     NSString *myString = [userDefaultes stringForKey:@”myString”];
  83.     txtNSString.text = myString;
  84.     //读取NSDate日期类型的数据
  85.     NSDate *myDate = [userDefaultes valueForKey:@”myDate”];
  86.     NSDateFormatter *df = [[NSDateFormatter alloc] init];
  87.     [df setDateFormat:@”yyyy-MM-dd HH:mm:ss”];
  88.     txtNSDate.text = [NSString stringWithFormat:@”%@”,[df stringFromDate:myDate]];
  89.     //读取数组NSArray类型的数据
  90.     NSArray *myArray = [userDefaultes arrayForKey:@”myArray”];
  91.     NSString *myArrayString = [[NSString alloc] init];
  92.     for(NSString *str in myArray)
  93.     {
  94.         NSLog(@”str= %@”,str);
  95.         myArrayString = [NSString stringWithFormat:@”%@  %@”, myArrayString, str];
  96.         [myArrayString stringByAppendingString:str];
  97. //        [myArrayString stringByAppendingFormat:@”%@”,str];
  98.         NSLog(@”myArrayString=%@”,myArrayString);
  99.     }
  100.     txtNSArray.text = myArrayString;
  101.     //读取字典类型NSDictionary类型的数据
  102.     NSDictionary *myDictionary = [userDefaultes dictionaryForKey:@”myDictionary”];
  103.     NSString *myDicString = [NSString stringWithFormat:@”name:%@, age:%d”,[myDictionary valueForKey:@”name”], [[myDictionary valueForKey:@”age”] integerValue]];
  104.     txtNSDictionary.text = myDicString;
  105. }
  106. @end

好了,运行一下,可以看到xib文件中的各种数据已经绑定上了吧?1

再次运行的时候,可以把viewDidLoad中的  [self  saveNSUserDefaults];  这一行注释掉,让程序直接读取而不存储数据,发现以前保存的数据仍然可以读取到界面上。

嘻嘻,很简单吧,就这样就可以是实现数据的存储了。

下面讲一下原理:

你可能会问一个问题:NSUserDefautls将数据存储在什么地方了???我都没有显示的指定路径???很疑惑吧。。。。

用NSUserDefaults存储的数据下次程序运行的时候依然存在,它把数据存储在什么地方了?如何能够清除?

其实它存储在应用程序内置的一个plist文件里,这个可以根据路径看到。
比如说这个是你的程序沙盒位置
/UsersLibrary/Application Support/iPhoneSimulator/4.1/Applicati*****/29788E40-AF47-45A0-8E92-3AC0F501B7F4/,(这个是应用程序对应在mac上的位置)
这个下面有/Library/Prefereces,里面有个plist文件,存储的就是你的userDefaults
想要删掉的话,用removeObjectForKey或者删掉沙盒,也就是你的应用程序然后重新安装。

解决 “this class is not key value coding-compliant for the key view”问题

在iPhone开发中,由于喜欢比较干净的环境,所以放弃了StoreBoard,改用手工创建xib文件和controller,结果删除storeboard、添加xib及其控制后,怎么也无法启动,报错:

Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<UIApplication 0x14568a10> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key view.’

*** First throw call stack:

(0x2ef1ef4b 0x3935f6af 0x2ef1ec61 0x2f85e18b 0x2f86fdd5 0x2ee8ee6f 0x319f0f87 0x319f27eb 0x3190a94b 0x316fc265 0x3169741f 0x31696721 0x316fbb3d 0x33b7a70d 0x33b7a2f7 0x2eee99df 0x2eee997b 0x2eee814f 0x2ee52c27 0x2ee52a0b 0x316fadd9 0x316f6049 0xa4235 0x39867ab7)

libc++abi.dylib: terminating with uncaught exception of type NSException

(lldb)

 

stackoverflow中的解释是File’s Owner没有跟他的view连接导致,实际上我试验过,根本不是,而是因为我的app delegate中的代码也是自己写的,通过手动装载xib文件:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[RootViewController alloc] initWithNibName:@"RootView" bundle:nil];

    UINavigationController *nationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];

    self.window.rootViewController = nationController;
    [self.window makeKeyAndVisible];
    return YES;
}

 

一是想到,既然我手动装载了RootView,那么就没必要在File’s Owner中将RootViewController关联给xib:

1

 

一是马上又想到,既然是我自己在app delegate中装载了根视图,那么在项目设置中也没必要指定启动视图,在Main Interface中留空就行:

2

而我在删除storeboard时想到,既然默认启动是storeboard,现在被删除了,是不是也要指定一个默认装载视图,于是在Main Interface中填入了一个rootview。

就是第二个想法修复了我的问题,原因嘛,只能是猜测:你自己手工装载了一份;由于你又在Main Interface中指定了一个,所以系统编译时会指定要启动的默认视图,结果你手工装载的视图把系统默认装载的视图替换了,导致错误的产生。

 

 

 

 

 

 

CoreTelephony框架

iOS 4.0 的官方 API 里头,多了一个叫做 Core Telephony 的 framework;一直以来 Core Telephony 都是 private API,现在开放出来,但是从文件来看,里头根本没有几行,既没有告诉你应该怎么用,也没有范例,你从 framework 里头寥寥四个 class 的 header 中,也搞不清楚,究竟可以把这个东西用在什么用途上。

目前只知道可以拿来做两件事情:1. 知道目前你这只 iPhone 用的是哪个电信商的服务;2. 知道现在 iPhone 是不是在打电话。

※ 电信商资讯

用 CTTelephonyNetworkInfo 与 CTCarrier 这两个 class,就可以取得电信商资讯,例如:

CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *carrier = info.subscriberCellularProvider;
NSLog(@"carrier:%@", [carrier description]);

倒出来的结果像是:

CTCarrier (0x140dc0) {

    Carrier name: [中国移动]
    Mobile Country Code: [466]
    Mobile Network Code:[92]
    ISO Country Code:[tw]
    Allows VOIP? [YES]
}

 

然后,如果你对 CTTelephonyNetworkInfo 喂一个 block 进去,像是:

info.subscriberCellularProviderDidUpdateNotifier = ^(CTCarrier *carrier) {NSLog(@"carrier:%@", [carrier description]);};

 

如 此一来,当你的 iPhone 漫游到了其他网路的时候,就会执行你这段 block,但光是知道手机现在漫游在哪个电信商的网路里头,大概能做的,就是一些跟电信商关系密切的服务之类,你或许可以决定软体里头有哪些功能,一定 要在某个电信商的网路才能用;电信商自己做 iPhone 软体的时候大概会想做这种事情。
※ 通话资料

用 CTCallCenter 与 CTCall 这两个 class,便可以知道目前 iPhone 是否在通话中。CTCallCenter 的用途是用来监控是不是有电话打进来、正在接听、或是已经挂断,而 CTCall 则是将每一则通话事件包装成一个物件。我们先写一小段程式-

CTCallCenter *center = [[CTCallCenter alloc] init];
center.callEventHandler = ^(CTCall *call) {
    NSLog(@"call:%@", [call description]);
};

然后,在实机上执行,接著打通电话到这支 iPhone 上,打通电话进去,然后马上挂断(人好端端的,干嘛为了测试程式跟自己的电话费帐单过不去呢?)就可以看到 iPhone 执行了我们的 block,把 CTCall 物件倒出来:

CTCall (0x143400) {
    callState: [CTCallStateIncoming]
    Call ID: [CE5F9337-1990-4254-8797-1CCEA85B061B]
}
CTCall (0x10bac0) {
    callState: [CTCallStateDisconnected]
    Call ID: [CE5F9337-1990-4254-8797-1CCEA85B061B]
}

 

CTCall 物件只有两个属性,一是通话状态(来电中、通话中…),二是这则通话的 unique id,除此之外没有其他资讯,你没办法知道这通电话是从哪里打来的,只能知道有电话进来而已,也没办法透过这个 API 打电话出去。

大抵上可以想到的用途,就是当你的程式执行到一半的时候,程式流程被电话打断,这时候就可能要中断原本正在做的事情,在通话结束之后恢复。

最后,CTCallCenter 与 CTTelephonyNetworkInfo,在模拟器上是没有办法用的,呼叫 alloc、init 之后回传的结果只会是 nil。

 

 

一种简便获取iPhone IMEI 的方法

 

使用CoreTelephony库,它是一个公开的framework,但很多API没有出现在文档中

iPhone私有API跟电话相关的CoreTelephony 里面提到了很多API, 其中有些可能跟电话录音有关系.

其中 _CTServerConnectionCopyMobileIdentity 就是用来获取IMEI的

#import

struct CTServerConnection
{
int a;
int b;
CFMachPortRef myport;
int c;
int d;
int e;
int f;
int g;
int h;
int i;
};

struct CTResult
{
int flag;
int a;
};

struct CTServerConnection * _CTServerConnectionCreate(CFAllocatorRef, void *, int *);

void _CTServerConnectionCopyMobileIdentity(struct CTResult *, struct CTServerConnection *, NSString **);
保存为 CoreTelephony.h

#import "CoreTelephony.h"

struct CTServerConnection *sc=NULL;
struct CTResult result;

void callback() { }

int main()
{
sc = _CTServerConnectionCreate(kCFAllocatorDefault, callback, NULL);

NSString *imei;
_CTServerConnectionCopyMobileIdentity(&result, sc, &imei);

NSLog (@"zhiwei's IMEI is %@", imei);

return 0;
}

IMSI

// 需要 CoreTelephony framework
// 在文件开头加入
extern NSString* CTSIMSupportCopyMobileSubscriberIdentity();

+ (NSString*) getDeviceIMSI {
    return CTSIMSupportCopyMobileSubscriberIdentity();
}

 

本机电话号码

// 需要 CoreTelephony framework
// 在文件开头加入
extern NSString* CTSettingCopyMyPhoneNumber();

+ (NSString*) getPhoneCodeByCT {
    return CTSettingCopyMyPhoneNumber();
}

 

本文转自:http://blog.csdn.net/kingkong1024/article/details/8363726

获得通讯录中联系人的所有属性

ABAddressBookRef addressBook = ABAddressBookCreate();

    CFArrayRef results = ABAddressBookCopyArrayOfAllPeople(addressBook);

    for(int i = 0; i < CFArrayGetCount(results); i++)
    {
        ABRecordRef person = CFArrayGetValueAtIndex(results, i);
        //读取firstname
        NSString *personName = (NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);
        if(personName != nil)
            textView.text = [textView.text stringByAppendingFormat:@"\n姓名:%@\n",personName];
        //读取lastname
        NSString *lastname = (NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);
        if(lastname != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",lastname];
        //读取middlename
        NSString *middlename = (NSString*)ABRecordCopyValue(person, kABPersonMiddleNameProperty);
        if(middlename != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",middlename];
        //读取prefix前缀
        NSString *prefix = (NSString*)ABRecordCopyValue(person, kABPersonPrefixProperty);
        if(prefix != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",prefix];
        //读取suffix后缀
        NSString *suffix = (NSString*)ABRecordCopyValue(person, kABPersonSuffixProperty);
        if(suffix != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",suffix];
        //读取nickname呢称
        NSString *nickname = (NSString*)ABRecordCopyValue(person, kABPersonNicknameProperty);
        if(nickname != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",nickname];
        //读取firstname拼音音标
        NSString *firstnamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonFirstNamePhoneticProperty);
        if(firstnamePhonetic != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",firstnamePhonetic];
        //读取lastname拼音音标
        NSString *lastnamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonLastNamePhoneticProperty);
        if(lastnamePhonetic != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",lastnamePhonetic];
        //读取middlename拼音音标
        NSString *middlenamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonMiddleNamePhoneticProperty);
        if(middlenamePhonetic != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",middlenamePhonetic];
        //读取organization公司
        NSString *organization = (NSString*)ABRecordCopyValue(person, kABPersonOrganizationProperty);
        if(organization != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",organization];
        //读取jobtitle工作
        NSString *jobtitle = (NSString*)ABRecordCopyValue(person, kABPersonJobTitleProperty);
        if(jobtitle != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",jobtitle];
        //读取department部门
        NSString *department = (NSString*)ABRecordCopyValue(person, kABPersonDepartmentProperty);
        if(department != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",department];
        //读取birthday生日
        NSDate *birthday = (NSDate*)ABRecordCopyValue(person, kABPersonBirthdayProperty);
        if(birthday != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",birthday];
        //读取note备忘录
        NSString *note = (NSString*)ABRecordCopyValue(person, kABPersonNoteProperty);
        if(note != nil)
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",note];
        //第一次添加该条记录的时间
        NSString *firstknow = (NSString*)ABRecordCopyValue(person, kABPersonCreationDateProperty);
        NSLog(@"第一次添加该条记录的时间%@\n",firstknow);
        //最后一次修改該条记录的时间
        NSString *lastknow = (NSString*)ABRecordCopyValue(person, kABPersonModificationDateProperty);
        NSLog(@"最后一次修改該条记录的时间%@\n",lastknow);

        //获取email多值
        ABMultiValueRef email = ABRecordCopyValue(person, kABPersonEmailProperty);
        int emailcount = ABMultiValueGetCount(email);    
        for (int x = 0; x < emailcount; x++)
        {
            //获取email Label
            NSString* emailLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(email, x));
            //获取email值
            NSString* emailContent = (NSString*)ABMultiValueCopyValueAtIndex(email, x);
            textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",emailLabel,emailContent];
        }
        //读取地址多值
        ABMultiValueRef address = ABRecordCopyValue(person, kABPersonAddressProperty);
        int count = ABMultiValueGetCount(address);    

        for(int j = 0; j < count; j++)
        {
            //获取地址Label
            NSString* addressLabel = (NSString*)ABMultiValueCopyLabelAtIndex(address, j);
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",addressLabel];
            //获取該label下的地址6属性
            NSDictionary* personaddress =(NSDictionary*) ABMultiValueCopyValueAtIndex(address, j);        
            NSString* country = [personaddress valueForKey:(NSString *)kABPersonAddressCountryKey];
            if(country != nil)
                textView.text = [textView.text stringByAppendingFormat:@"国家:%@\n",country];
            NSString* city = [personaddress valueForKey:(NSString *)kABPersonAddressCityKey];
            if(city != nil)
                textView.text = [textView.text stringByAppendingFormat:@"城市:%@\n",city];
            NSString* state = [personaddress valueForKey:(NSString *)kABPersonAddressStateKey];
            if(state != nil)
                textView.text = [textView.text stringByAppendingFormat:@"省:%@\n",state];
            NSString* street = [personaddress valueForKey:(NSString *)kABPersonAddressStreetKey];
            if(street != nil)
                textView.text = [textView.text stringByAppendingFormat:@"街道:%@\n",street];
            NSString* zip = [personaddress valueForKey:(NSString *)kABPersonAddressZIPKey];
            if(zip != nil)
                textView.text = [textView.text stringByAppendingFormat:@"邮编:%@\n",zip];    
            NSString* coutntrycode = [personaddress valueForKey:(NSString *)kABPersonAddressCountryCodeKey];
            if(coutntrycode != nil)
                textView.text = [textView.text stringByAppendingFormat:@"国家编号:%@\n",coutntrycode];    
        }

        //获取dates多值
        ABMultiValueRef dates = ABRecordCopyValue(person, kABPersonDateProperty);
        int datescount = ABMultiValueGetCount(dates);    
        for (int y = 0; y < datescount; y++)
        {
            //获取dates Label
            NSString* datesLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(dates, y));
            //获取dates值
            NSString* datesContent = (NSString*)ABMultiValueCopyValueAtIndex(dates, y);
            textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",datesLabel,datesContent];
        }
        //获取kind值
        CFNumberRef recordType = ABRecordCopyValue(person, kABPersonKindProperty);
        if (recordType == kABPersonKindOrganization) {
            // it's a company
            NSLog(@"it's a company\n");
        } else {
            // it's a person, resource, or room
            NSLog(@"it's a person, resource, or room\n");
        }

        //获取IM多值
        ABMultiValueRef instantMessage = ABRecordCopyValue(person, kABPersonInstantMessageProperty);
        for (int l = 1; l < ABMultiValueGetCount(instantMessage); l++)
        {
            //获取IM Label
            NSString* instantMessageLabel = (NSString*)ABMultiValueCopyLabelAtIndex(instantMessage, l);
            textView.text = [textView.text stringByAppendingFormat:@"%@\n",instantMessageLabel];
            //获取該label下的2属性
            NSDictionary* instantMessageContent =(NSDictionary*) ABMultiValueCopyValueAtIndex(instantMessage, l);        
            NSString* username = [instantMessageContent valueForKey:(NSString *)kABPersonInstantMessageUsernameKey];
            if(username != nil)
                textView.text = [textView.text stringByAppendingFormat:@"username:%@\n",username];

            NSString* service = [instantMessageContent valueForKey:(NSString *)kABPersonInstantMessageServiceKey];
            if(service != nil)
                textView.text = [textView.text stringByAppendingFormat:@"service:%@\n",service];            
        }

        //读取电话多值
        ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
        for (int k = 0; k<ABMultiValueGetCount(phone); k++)
        {
            //获取电话Label
            NSString * personPhoneLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(phone, k));
            //获取該Label下的电话值
            NSString * personPhone = (NSString*)ABMultiValueCopyValueAtIndex(phone, k);

            textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",personPhoneLabel,personPhone];
        }

        //获取URL多值
        ABMultiValueRef url = ABRecordCopyValue(person, kABPersonURLProperty);
        for (int m = 0; m < ABMultiValueGetCount(url); m++)
        {
            //获取电话Label
            NSString * urlLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(url, m));
            //获取該Label下的电话值
            NSString * urlContent = (NSString*)ABMultiValueCopyValueAtIndex(url,m);

            textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",urlLabel,urlContent];
        }

        //读取照片
        NSData *image = (NSData*)ABPersonCopyImageData(person);

        UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake(200, 0, 50, 50)];
        [myImage setImage:[UIImage imageWithData:image]];
        myImage.opaque = YES;
        [textView addSubview:myImage];

    }

    CFRelease(results);
    CFRelease(addressBook);

 

ios实现通讯录的查询与删除

os提供了对通讯录操作的组建,其中一个是直接操作通讯录,另一个是调用通讯录的UI组建。实现方法如下:

添加AddressBook.framework到工程中。

1

代码实现:

    -(IBAction)onClickbutton:(id)sender
    {
        NSMutableArray* personArray =[[[NSMutableArray alloc] init] autorelease];
        ABAddressBookRef addressBook =ABAddressBookCreate();
        NSString*firstName,*lastName,*fullName;
        personArray =(NSMutableArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
        if([sender tag]==0){

            for(id *person in personArray)
            {
                firstName =(NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);
                firstName =[firstName stringByAppendingFormat:@" "];
                lastName =(NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);   
                fullName =[firstName stringByAppendingFormat:@"%@",lastName];
                NSLog(@"===%@",fullName);
                ABMultiValueRef phones =(ABMultiValueRef)ABRecordCopyValue(person, kABPersonPhoneProperty);
                for(int i =0;i <ABMultiValueGetCount(phones); i++)
                { 
                    NSString*phone =(NSString*)ABMultiValueCopyValueAtIndex(phones, i);
                    NSLog(@"===%@",phone);
                }
                ABMultiValueRef mails =(ABMultiValueRef)ABRecordCopyValue(person, kABPersonEmailProperty);
                for(int i =0;i <ABMultiValueGetCount(mails); i++)
                { 
                    NSString*mail =(NSString*)ABMultiValueCopyValueAtIndex(mails, i);
                    NSLog(@"==%@",mail);
                }       
            }   
        }else{
            //删除信息
            //返回所有联系人到一个数组中
            CFArrayRef personArray =ABAddressBookCopyArrayOfAllPeople(addressBook);
            CFIndex personCount =ABAddressBookGetPersonCount(addressBook);
              for(int i =0;i<personCount;i++){
                  ABRecordRefref=CFArrayGetValueAtIndex(personArray, i);
                  CFStringRef firstName1 =ABRecordCopyValue(ref, kABPersonFirstNameProperty);
                  CFStringRef lastName1 =ABRecordCopyValue(ref, kABPersonLastNameProperty);
                  NSString*contactFirstLast =[NSString stringWithFormat: @"%@%@",(NSString*)firstName1,(NSString*)lastName1];
                if([contactFirstLast isEqualToString:@"徐梦"]){
                    //删除联系人
                    ABAddressBookRemoveRecord(addressBook,ref,nil);
                }
            }
            //保存电话本
            ABAddressBookSave(addressBook,nil);  
            //释放内存
            //CFRelease(personRef);
    //        CFRelease(addressbookRef); 
        }
    }

 

本文转自:http://blog.csdn.net/kingkong1024/article/details/8364037

Installing Cocos2d for iPhone Development

Coco2d is an SDK geared toward games development for iPhone and iTouch.   It was originally written for Phyton language.  It is licensed under GNU LGPL.

Where To Download:

http://code.google.com/p/cocos2d-iphone/

Requirements:

  • Mac running Mac OS that supports the iPhone SDK (mine is Mac OS 10.5.6)
  • Xcode version 3 or newer
  • iPhone SDK

For help on installing Xcode and iPhone SDK, and where to get them, see http://permadi.com/blog/?p=130.

Steps To Install

1. Download from http://code.google.com/p/cocos2d-iphone/downloads/list.

2. Extract and copy to the files your Library folder (can be any folder you want to designate).  I put mine on a Library folder.

1

Congratulations.  You have cocos2d installed.  Now comes the more difficult part (just because there’s no documentation).

Let’s try out the samples so we can see what cocos2d is capable of.

You can double click the project file (cocos2d-iPhone.xcodeproj) which should be located in the folder where you extracted cocos2d package.  Or you can run Xcode and do File->Open.

You should see the project window with the following Groups & Files:

2

If you do Build And Go now, either nothing happens or the iPhone simulator launches with a blank screen.  You should expand theTargets group instead.  When you do that, you’l see the list of exectables (Atlas Demo, AttachDemo, EaseDemo, and so on).  Control-Click (or right-click) on any of the demo and do Build on one of the “Demo.”

build1

After the selected demo is built, you can run it by expanding the Executables tree. You should see the demo that you build on the Executables tree. Control-Click (or right-click) on the item that has the same demo name as the one you built earlier.  (Note: If you don’t see the Start menu, then you have not built the executable.  Do the previous step first.)

startcocos2dexample1

Here’s what AccelViewportDemo looks like.

acceldemo

Try the other ones.  They are cool.

Make sure also to build the cocos2d library for your target platform, so you can use the libraries without having to recompile every time.  To do this, select the Active SDK and Active Build Configuration that you need (or build them all).  You can find the build result in abuild under the folder where you installed cocos2d.  Select cocos2d in the Targets group, and do Control-click, select build cocos2d.

cocos2dlib

 

To: Hello World Sample Appilcation

 

iBeacon技术,苹果迟迟不肯支持NFC原来是为了另立山头?

 121911tybphw6o0m0wzkib
虎嗅注:苹果发布会真正的闪光点常常被“杂音”淹没——9月10日的发布会上,iPhone 5C的五种颜色和高昂定价让很多人忽略A7处理器这款第一次被运用在智能手机上的64位ARM架构处理器,领先于高通、Nvidia和三星;而在今年6月的WWDC上,iOS 7的“扁平化”风格也使人们忽略了其中的一些重要的新特性,比如iBeacon技术——到现在为止还有很多人不知道这是什么。
最近,国外科技媒体Gigaom上有一篇文章,其中详细介绍了苹果用以对抗NFC(近场通讯)的iBeacon技术,并认为该技术将是苹果未来重点发展对象之一。本文由腾讯数码编译,大意如下:
在今年六月举行的WWDC上,作为iOS 7中最重要的新特性之一,苹果正式对外发布了iBeacon。同时,一家名为Estimote的公司日前也宣布将推出支持iBeacon技术的基站。
Estimote为什么要支持iBeacon技术?因为iBeacon技术不仅为诸如室内地图等新兴应用提供了发展平台,能够让互联网更容易地融入我们的日常生活,甚至还有可能击败目前最有希望成为无线支付方式的NFC技术。
iBeacon技术和低耗蓝牙技术
通过使用低功耗蓝牙技术(Bluetooth Low Energy,也就是通常所说的Bluetooth 4.0或者Bluetooth Smart),iBeacon基站可以创建一个信号区域,当设备进入该区域时,相应的应用程序便会提示用户是否需要接入这个信号网络。通过能够放置在任何物体中的小型无线传感器和低功耗蓝牙技术,用户便能使用iPhone来传输数据。
举个例子,假如你带着一部iPhone 5s(运行iOS 7并支持iBeacon)走入一家大型商场的店铺,同时这也意味着你已经进入了这家店铺的iBeacon信号区域。然后iBeacon基站便可以向你的iPhone传输各种信息,比如优惠券或者是店内导航信息,甚至当你走到某些柜台前面时,iBeacon还会提供个性化的商品推荐信息。也就是说在iBeacon基站的信息区域内,用户通过手中的智能手机便能够获取个性化的微型位置信息以及通知。
iBeacon不仅能够为用户提供他们所需要的信息,甚至和NFC技术一样,用户也能通过iBeacon来完成支付。除此之外,每个iBeacon基站内置有加速度计、闪存、ARM架构处理器以及蓝牙模块,而一小块纽扣电池便能为一个iBeacon基站提供长达两年的续航时间。
低功耗蓝牙技术的最大特点便在于低功耗,从而能使设备拥有更长的续航时间。不过低功耗蓝牙技术仅支持较低的文件传输速率,因此可以用于可穿戴式智能设备之间的信息传送,但却不能完成像传输音频这样的任务。从目前的状况来看,只有Android 4.3才支持低功耗蓝牙技术,因此这就是为什么老款Android机型不支持某些导航应用的原因。
传输范围广,成本低廉的iBeacon技术
从技术角度讲,更广的信息传输范围是iBeacon相比于NFC最大的优势。对于如今的NFC技术,虽然NFC标签的价格要比NFC芯片便宜得多,但是NFC标签的理论有效距离只有20cm,而最理想的使用距离只有4cm,范围可谓非常之小。
同时,手机等移动设备必须搭载NFC芯片才能支持NFC通讯;而iBeacon基站虽然要比NFC芯片的价格稍微昂贵一些,但是iBeacon的信息传输距离可达50m左右,而且如今几乎每部手机都支持蓝牙技术,但却不一定配备有NFC芯片。
让我们回到前面的那个例子中去,假设一家店铺的面积为16000平方米左右,而如果每个iBeacon基站的最远传输距离为50m的话,那么可以覆盖的面积大约在2500平方米左右,因此这家店铺只需要购买7个iBeacon基站便能够满足要求。
而从Estimote公司给出的价格来看,3个iBeacon基站的预购价格为99美元(约合人民币610元)。需要注意的是,虽然Estimote公司推出的iBeacon基站的最远传输距离为50m,但他们推荐在10m范围内的使用效果最好。如果按照Estimote公司给出的建议的话,每个iBeacon基站的覆盖范围是100平方米左右,那么总共需花费约5000美元左右。
如果使用NFC标签的话,按每个标签10美分(约合人民币0.61元)来计算的话,10万件商品就需要花费10000美元,是使用iBeacon基站的两倍。
或许将诞生一系列新应用
从iBeacon的特点来说,该技术很可能会促进一系列室内地图应用的诞生。由于在室内时,有各种障碍物的阻挡,因此GPS信号非常微弱,因此无法实现导航。这也是为什么虽然谷歌现在已经建立了部分地区的室内地图,但是还无法实现室内导航的原因。而这也正是iBeacon技术的优势所在。
借助智能手机,用户可以连接到最近的iBeacon基站,从而获得该基站的GPS位置信息,从而知道目前所处的地点。当用户进入或离开某个iBeacon基站的通信范围时都会收到相应的通知信息,从而实现导航的目的。
对抗NFC,低功耗蓝牙技术才是将网络带进现实的最好方法?
每次新款iPhone发布之前,外界都有人预测新款iPhone将会搭载NFC技术,不过事实证明这都只是外界一厢情愿的想法罢了。在iOS 7中,苹果增加了AirDrop无线分享功能,而苹果公司软件工程高级副总裁Craig Federighi认为“没有必要为了分享文件而走到某个人的面前,然后仅仅是为了触碰一下手机”,而这也是苹果对于NFC技术的看法。
为了让网络与现实世界结合到一起,各种传感器的起到了非常重要的作用。对于一个传感器来说,尺寸、价格、网络连接性都是很关键的指标。如果能够远程遥控各种传感器的话,那么传感器的用途可以说是无穷无尽的。比如在回家的路上开启家中的电源,根据天气控制冰箱的温度,通过手机控制房间的灯光等等。Estimote表示他们正在努力改进iBeacon基站以进一步缩减价格和体积,从而使iBeacon更加实用。
既然苹果能够通过使用低功耗蓝牙技术的iBeacon来解决数据的短距离传输问题,那么又有什么理由让人们互相触碰手机呢?而且相比于NFC技术来说,蓝牙能够提供NFC无法实现的功能。

15道烧糊大脑的苹果面试题

以下15道题是从求职论坛GlassDoor摘选出的真实的苹果面试题目:

1.桌子上放着一部老款iPhone。你所了解的iPhone使用的材料有哪些?

面试职位:产品设计工程师

苹果产品设计工程师的重要任务之一就是控制供应成本,以降低手机的价格。

苹果的手机定价非常具有竞争力,因此面试者必须懂得如何在特定成本区间内设计产品。懂得材料及其性质能够帮助设计师在维持低成本的同时设计出更好的产品。

2.形容一下你平时使用苹果产品的情况。

面试职位:销售

如果你想销售苹果的产品,你最好已经是苹果产品的用户。

不用说,苹果当然不会雇佣一个从来没有使用过iPhone的人做销售。

3.如果有500台洗衣机被测试实验室认定为不合格,你如何找出不合格的原因以及解决办法?

面试职位:产品质量工程师

如果制造过程中出现任何故障,你可能会失去价值数相当于百台iPhone的收入–这个数字也有可能是数万台或数十万台。

如果你想担任产品质量工程师,那么请首先确认,不管出现什么问题,你都能发现故障并找出原因所在。尤其是当问题出现在供应链早期的时候,这一点更加重要。

4.在极其有限的资源环境下,如何在user-space框架下实现处理网络、文件系统、UI系统等的线程模型?

面试职位:软件工程师

编写一组代码并使之运行非常容易,但要让它高效率运行却很难。

尤其是如果你在为一款手机设计软件。你必须使用低功耗的芯片,以维持较长的续航时间。

5.你如何计算出中国供应给美国的苹果的数量?

面试职位:材料项目经理

面试官所指的是苹果。你懂的,一种水果。

但这仍然是一道相当基础的供应链题目。如果你要担任供应链管理职位,你需要清楚地知道供应商有哪些,他们能提供的材料有哪些。

苹果优势的一个重要来源就是,他们买断了制造智能手机所需的所有最好的零部件。如果你对整个供应链都了如指掌,你就能降低成本。

6.使用运算放大器设计一个LED驱动电路。

面试职位:硬件工程师

许多情况下,你设计的产品不会工作在最适宜的环境下。有时会太热,有时会太冷,甚至会掉进水里。

你必须保证你的硬件在这些非最佳环境下仍然能够运行。

7.你如何诊断缓冲区溢出?

面试职位:软件工程师

许多时候,判定一个工程师是否属于最优秀的行列,最好办法就是问他们如何解决一个问题。

如果出现缓冲区溢出,结果可能是灾难性的。因此,如果你想测试手下的工程师面临极端问题时将会如何反应,这个问题很适合。

8.现在有100个标记过的电灯泡。第一个人经过这些灯时,点亮所有的灯,第二个人经过时每隔一盏灯就切换开关一次,第三个人经过时每隔两盏灯切换开关一次。请问,当第100个人经过时,还剩多少盏亮着的灯?

面试职位:高级软件工程师

苹果面试官们并非全部使用原创的面试题,他们有时也会使用可汗学院(Khan Academy)设计的脑筋急转弯。

但是,这道题仍然是一道需要运用巧妙数学原理解决的很复杂的题目,很适合测试工程师解决问题的能力。

9.你平时看科技新闻多不多?

面试职位:Mac天才

如果你想在苹果零售店里工作,你需要知道普通大众对苹果在新闻上的印象如何。

面试官想知道你是否平时经常看TechCrunch、瘾科技或腾讯科技。

10.现在有一个6×6的方格,从左上角的点出发,只能向右或向下移动,请问到达右下角需要多少步?

面试职位:高级软件工程师

这种问题被称为步数计算题。这是最基本的测试思维方式而非要求正确答案的题目之一。

苹果会问高级工程师这种脑筋急转弯,这似乎并不让人觉得惊讶。

11.你如何确定表面曲率的连续性?

面试职位:CAD雕塑师

苹果会制造非常多的设备模型,如iPhone和iPad的原型机等。这些都需要经过严格的测试,因此苹果需要招聘能够快速做出模型的人。

但这些模型仍然需要与苹果的其他设备一样完美。因此,苹果必须确定雕塑师和设计师拥有完美主义特质,即便是玻璃的形状也要精益求精。

12.在一个相互连接的点组成的列表中,找到中间节点。

面试职位:Cocoa camp

苹果希望软件工程师能够给出一个巧妙的解决方案。

例如,可以使用两个“指针”,其中一个指针顺着每一个点依次通过,而另一个指针则每走一步跳过一个点。当第二个指针达到终点,第一个指针刚好达到中间节点。

13.如果你能为远程控制功能新增一项技术,你希望增加什么样的技术?

面试职位:天才吧Specialist专家

这个问题很古怪–或许苹果是在测试面试者是否为iPhone粉丝。

天才吧的Specialist必须是大大的苹果粉丝。

14.想出5种在铁板上打洞的办法。

面试职位:产品设计工程师

苹果希望设计和硬件工程师既对技术无比精通,同时富有创新精神。

因此,即使是在铁板上打一个洞这么简单的事也可能有多种办法。苹果在测试面试者的创意能力。

15.你高中时期最容易进入或最适合的社团是什么?

面试职位:天才吧Specilist专家

如果你需要一眼看出零售店内哪些人更有可能买苹果产品,你必须拥有慧眼识人的能力。

Specialist必须将顾客进行分类,然后尽快弄明白他们是否真的想购买某种产品。想购买产品的那些人往往都有一些共同点。

本文摘自网络

Processor of the iPods

What processor do the iPod, iPod mini, iPod nano, iPod touch, and iPod shuffle models use?

Apple provides no official information regarding the processors used to power the iPod models.

Starting with the iPod nano 2nd Gen, the company has gone as far as having the processor custom branded with an Apple logo to make it more difficult to determine its origins. However, the below chart is believed to be accurate.

iPod Name Processor Details
iPod (Original/Scroll) PP5002 PortalPlayer PP5002 “system on a chip” with dual embedded 90 MHz ARM 7TDMI processors.
iPod 2nd Gen PP5002  
iPod 3rd Gen 10/15/30 PP5002  
iPod 3rd Gen 10/20/40 PP5002  
iPod 3rd Gen 15/20/40 PP5002  
iPod 4th Gen ClickWheel PP5020 PortalPlayer PP5020 “system on a chip” with dual embedded variable speed 80 MHz ARM 7TDMI processors.
iPod U2 4th Gen PP5020  
iPod photo (30) PP5020  
iPod photo (40/60) PP5020  
iPod Color Display PP5020  
iPod U2 Edition (Color) PP5020  
iPod mini PP5020  
iPod mini 2nd Gen PP5020  
iPod 5th Gen (Video) PP5021C PortalPlayer PP5021C “system on a chip” with dual embedded variable speed 80 MHz ARM 7TDMI processors. For video decoding, these models use a Broadcom VideoCore BCM2722 processor.
iPod U2 5th Gen PP5021C  
iPod 5th Gen – Enhanced PP5021C The “Enhanced” 5th Gen iPod models are believed to use the same processors as the 5th Gen models.
iPod U2 5th Gen Enh. PP5021C  
iPod classic 6th Gen Samsung ARM Apple provides no information on the processor used in the iPod classic (6th Gen) models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod classic (2008) Samsung ARM Apple provides no information on the processor used in the iPod classic (6th Gen/Late 2008) models, but it uses an Apple branded processor, believed to be a Samsung ARM like its predecessor.
iPod nano PP5021C PortalPlayer PP5021C “system on a chip” with dual embedded 80 MHz ARM 7TDMI processors.
iPod nano 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 2nd Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For in-depth speculation regarding all of the chips used, please refer to ArsTechnica’s iPod nano 2nd Gen “autopsy.”
iPod nano 2nd Gen RED Samsung ARM  
iPod nano 3rd Gen/Fat Samsung ARM Apple provides no information on the processor used in the iPod nano 3rd Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 4th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 4th Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 5th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 5th Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 6th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 6th Gen models, but it is believed to use a Samsung ARM like its predecessors.
iPod shuffle STMP 3550 Uses a 75 MHz SigmaTel D-Major STMP 3550 processor.
iPod shuffle 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 2nd Gen models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 3rd Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 3rd Gen models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 3rd Gen Color Samsung ARM Apple provides no information on the processor used in the iPod shuffle 3rd Gen (Colors) models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 4th Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 4th Generation models, but it uses an Apple branded processor, believed to be a Samsung ARM.
iPod touch Samsung ARM Apple provides no information on the processor used in the iPod touch models, but it uses an Apple branded processor, believed to be a Samsung ARM running at 400 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod touch 2nd Gen models, but third-party “teardowns” indicate that it uses an Apple branded Samsung ARM processor running at 533 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 3rd Gen Samsung ARM Apple provides no information on the processor used in the iPod touch 3rd Gen models, but third-party “teardowns” indicate that the 32 GB and 64 GB configurations use an Apple branded Samsung ARM processor running at 800 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 4th Gen Apple A4 Like the original iPad and iPhone 4, the iPod touch (4th Generation) uses a custom ARM-based “system on a chip” that Apple refers to as an “Apple A4” processor. It integrates the CPU, graphics, the memory controller, and I/O functions.
iPod touch “4.5” Gen Apple A4 The iPod touch “4.5” Gen uses the same Apple A4 processor as the 4th Gen model.

Should you have additional, or alternate, information about the processors used in the iPod please share.

iPhone 短信发送问题:号码被截断

  我的iPhone3GS,4.3.3的固件,如果给没保存在通讯录中的新号码发送新短信,则输入号码后,准备写短信时,上面输入的号码就被截断了(偶尔不会被截断),发送必然失败。
  这是iPhone固件的一个bug,5.0的固件已经修复了这个bug,升级到5.0就解决这个问题了。
  如果你不想升级固件,在输入手机号后按一下键盘上的“回行”就不会截断号码了。

iCloud 是什么?

最近一直被apple产品震撼。说实话,有些莫名其妙!可能是用惯了平庸的产品、平庸的或者根本就没有的设计,一切显得也很自然。但是当你用到了苹果的东西,每个细节都有可能“伤害”到你的感情:我以前活在一个怎样的一个世界里面?——我自己都觉得有些夸张。
现在我带你体验一下iCloud吧!
用浏览器就可以访问iCloud了。地址栏输入:icloud.com,回车,如果是第一次使用,会出现如下界面:
简洁而美观,乔布斯式的唯美,即使他已过世,你看到这个,仍然会想到他。
点击登录后出现如下的登录界面:
对于一个再平凡不过的登录界面,不管是开发者还是使用者,谁会想这么多啊?但是,真正想过了,那就不一样了。。。
如果是第一次登录,可能需要你选择一下语言和时区。
进入后,还是简单的界面,将你关心的功能呈现给你:
第一个,Mail功能
你可以点击Mail图标,进入你关联过的xxx@me.com邮箱:
点击左上角的云图标,可以返回主界面。
主界面中点击通讯录,通讯录是这样子的,与iOS其他产品中展示的通讯录一个样:
同样,点击左上角的云图标,可以返回主界面。
另一个是“查找我的iPhone”功能,如果你的iPhone不幸丢失,这就是为你准备的,它可以定位你的iPhone、发送声音、短信提示、远程锁定,或者,如果万不得已,远程抹除重要信息。
最后一个是iWork,用来存放或者同步你的文档:
在上面的切换条中,你可以在Keynote、Pages、Numbers应用文稿间来回切换。
Keynote:
Numbers:
遗憾的——至少我很需要的一个功能,可能是自建文件夹,可以往里面放任何我想放的东西。
下面就摘一段来自iCloud官方的文字介绍,借此你可以更多的了解一下iCloud:
====================================================
iCloud 是什么?

iCloud 可以存储音乐、照片、App、联系人和日历等,并将它们无线推送到你的 iOS 5 设备和电脑上。iCloud 可与你的 App 无缝集成,因此一切都能自动进行。

例如,如果在 Mac 或 Windows 电脑的 iTunes 中购买歌曲,它会出现在你的 iPod touch 和 iPad 中。在 iPhone 上拍下照片时,它会自动发送到你的 iPad 上。你可以在 iPhone 上开始创建 Pages 文件,并在 iPad 上润色修饰。无需将你的 iOS 设备插入基座,也不用将它与电脑同步。

iCloud 包含下列服务:

  • iTunes 云服务:你在 iTunes 中购买的音乐会自动出现在你的设备上。还可以下载你过去购买的音乐或电视节目。

    【注】iTunes 云服务的可用性因国家/地区而异。电视节目仅在美国提供。

  • 照片流:你在一台 iOS 设备上拍摄照片时,它会自动显示在你的其他设备上,无需进行同步。
  • 文稿云服务:如果在多台设备上安装了支持文稿云服务的 App,iCloud 可让你的文稿在各台设备上自动保持最新状态。
  • App 和图书:你购买的 App 和图书会自动出现在你的 iOS 设备上。也可以下载过去购买的 App 和图书。
  • 备份:iCloud 每天通过 Wi-Fi 备份你的 iOS 设备(在设备已接通电源并处于屏幕锁定状态时执行)。iCloud 会备份你购买的音乐和电视节目、App、图书、相机胶卷、设备设置、App 数据、主屏幕和应用程序布局、信息(iMessage、SMS 和 MMS)以及铃声。

    【注】只有部分国家/地区提供备份购买的音乐服务。备份购买的电视节目服务仅在美国提供。

  • 通讯录日历邮件:iCloud 可以存储你的日历和联系人,并让它们在所有设备上保持最新状态。有了 iCloud,你还可以获得一个 me.com 电子邮件帐户,将新邮件推送到你的设备上。iCloud 还会存储并更新你的书签提醒事项备忘录
  • 查找我的 iPhone、iPad、iPod touch 或 Mac:如果你忘了 iPhone、iPad、iPod touch 或 Mac 的存放位置,可以使用“查找我的 iPhone”(Find My iPhone) 帮助你在地图上查找其位置、以最高音量播放声音、发送信息、锁定屏幕,或者抹掉其数据。你可以通过任何电脑使用 icloud.com 上的“查找我的 iPhone”Web 应用程序,或在 iOS 设备上下载并使用免费的 App。
  • 查找我的朋友:借助 iOS 5 设备(iPhone、iPad 或 iPod touch)上的“查找我的朋友”免费应用程序,您可以轻松定位您的朋友和家人。
  • 回到我的 Mac:借助“回到我的 Mac”功能,你可以从 Internet 上的另一台 Mac 安全地远程连接你的 Mac,并且访问文件或控制其屏幕。

在使用 iCloud 之前,你需要先在运行 iOS 5 的 iPhone、iPad 或 iPod touch 设备或运行 OS X Lion v10.7.2 的 Mac 上注册 iCloud 帐户。如果你还没有 iCloud 帐户或尚未在所有设备上设置 iCloud,请立即设置 iCloud

如果已在设备上设置了 iCloud,请点按左侧的帮助主题(或使用搜索)来了解更多信息。

【注】访问 icloud.com 时,请务必使用建议的浏览器

iPhone开发:Working With USB Device Interfaces

本文来自apple开发者网站:http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/USBBook/USBDeviceInterfaces/USBDevInterfaces.html#//apple_ref/doc/uid/TP40002645-TPXREF101

讲述了如何通过usb与外围设备交互信息,操作usb接口示例、源代码,非常有用。

This chapter describes how to develop a user-space tool that finds and communicates with an attached USB device and one of its interfaces. The sample code in this chapter is taken from the USB Notification Example sample project, available in /Developer/Examples/IOKit/usb of the Developer version of Mac OS X.

Using USB Device Interfaces

Applications running in Mac OS X get access to USB devices by using I/O Kit functions to acquire a device interface, a type of plug-in that specifies functions the application can call to communicate with the device. The USB family provides two types of device interface:

  • IOUSBDeviceInterface for communicating with the device itself
  • IOUSBInterfaceInterface for communicating with an interface in the device

Both device interfaces are defined in /System/Library/Frameworks/IOKit.framework/Headers/usb/IOUSBLib.h.

Communicating with the device itself is usually only necessary when you need to set or change its configuration. For example, vendor-specific devices are often not configured because there are no default drivers that set a particular configuration. In this case, your application must use the device interface for the device to set the configuration it needs so the interfaces become available.

The process of finding and communicating with a USB device is divided into two sets of steps. The first set outlines how to find a USB device, acquire a device interface of type IOUSBDeviceInterface for it, and set or change its configuration. The second set describes how to find an interface in a device, acquire a device interface of typeIOUSBInterfaceInterface for it, and use it to communicate with that interface. If you need to communicate with an unconfigured device or if you need to change a device’s configuration, you follow both sets of steps. If you need to communicate with a device that is already configured to your specification, you follow only the second set of steps. The sample code in “Accessing a USB Device” follows both sets of steps and extends them to include setting up notifications it can receive when devices are dynamically added or removed.

Follow this first set of steps only to set or change the configuration of a device. If the device you’re interested in is already configured for your needs, skip these steps and follow the second set of steps.

  1. Find the IOUSBDevice object that represents the device in the I/O Registry. This includes setting up a matching dictionary with a key from the USB Common Class Specification (see “Finding USB Devices and Interfaces”). The sample code uses the key elements kUSBVendorName and kUSBProductName to find a particular USB device (this is the second key listed in Table 1-2).
  2. Create a device interface of type IOUSBDeviceInterface for the device. This device interface provides functions that perform tasks such as setting or changing the configuration of the device, getting information about the device, and resetting the device.
  3. Examine the device’s configurations with GetConfigurationDescriptorPtr, choose the appropriate one, and call SetConfiguration to set the device’s configuration and instantiate the IOUSBInterface objects for that configuration.

Follow this second set of steps to find and choose an interface, acquire a device interface for it, and communicate with the device.

  1. Create an interface iterator to iterate over the available interfaces.
  2. Create a device interface for each interface so you can examine its properties and select the appropriate one. To do this, you create a device interface of typeIOUSBInterfaceInterface. This device interface provides functions that perform tasks such as getting information about the interface, setting the interface’s alternate setting, and accessing its pipes.
  3. Use the USBInterfaceOpen function to open the selected interface. This will cause the pipes associated with the interface to be instantiated so you can examine the properties of each and select the appropriate one.
  4. Communicate with the device through the selected pipe. You can write to and read from the pipe synchronously or asynchronously—the sample code in“Accessing a USB Device” shows how to do both.

Accessing a USB Device

This section provides snippets of sample code that show how to access a Cypress EZ-USB chip with an 8051 microcontroller core. The sample code follows the first set of steps in section “Using USB Device Interfaces” to find the Cypress EZ-USB chip in its default, unprogrammed state (also referred to as the “raw device”). It then configures the device and downloads firmware provided by Cypress to program the chip to behave as a device that echoes all information it receives on its bulk out pipe to its bulk in pipe.

Once the chip has been programmed, the device nub representing the default, unprogrammed device is detached from the I/O Registry and a new device nub, representing the programmed chip, is attached. To communicate with the programmed chip (also referred to as the “bulk test device”), the sample code must perform the first set of steps again to find the device, create a device interface for it, and configure it. Then it performs the second set of steps to find an interface, create a device interface for it, and test the device. The sample code also shows how to set up notifications for the dynamic addition and removal of a device.

If you want to build and run the sample code, open the USB Notification Example project (located in /Developer/Examples/IOKit/usb) in Xcode. You can observe the resulting tool’s status messages in the Xcode Run Log and terminate the tool by clicking the Terminate button. Alternatively, you can open a Terminal window, navigate to the location of the executable (for example, /Developer/Examples/IOKit/usb/USBNotification Example/build), run the tool, and terminate it by pressing Control-C. Note that the project also includes the bulktest.c file, which contains the firmware to download to the raw device, and the hex2c.h file, which defines the structure the firmware uses.

Definitions and Global Variables

The code in the USB Notification Example uses the definitions and global variables shown in Listing 2-1. The definition of USE_ASYNC_IO allows you to choose to use either synchronous or asynchronous calls to read from and write to the chip by commenting out the line or leaving it in, respectively. The definition of kTestMessagesets up a simple message to write to the device. The remaining definitions are specific to the Cypress EZ-USB chip.

Listing 2-1  Definitions and global variables

#define USE_ASYNC_IO    //Comment this line out if you want to use
                        //synchronous calls for reads and writes
#define kTestMessage        "Bulk I/O Test"
#define k8051_USBCS         0x7f92
#define kOurVendorID        1351    //Vendor ID of the USB device
#define kOurProductID           8193    //Product ID of device BEFORE it
                                        //is programmed (raw device)
#define kOurProductIDBulkTest   4098    //Product ID of device AFTER it is
                                        //programmed (bulk test device)
//Global variables
static IONotificationPortRef    gNotifyPort;
static io_iterator_t            gRawAddedIter;
static io_iterator_t            gRawRemovedIter;
static io_iterator_t            gBulkTestAddedIter;
static io_iterator_t            gBulkTestRemovedIter;
static char                     gBuffer[64];

The main Function

The main function in the USB Notification Example project (contained in the file main.c) accomplishes the following tasks.

  • It establishes communication with the I/O Kit and sets up a matching dictionary to find the Cypress EZ-USB chip.
  • It sets up an asynchronous notification to be called when an unprogrammed (raw) device is first attached to the I/O Registry and another to be called when the device is removed.
  • It modifies the matching dictionary to find the programmed (bulk test) device.
  • It sets up additional notifications to be called when the bulk test device is first attached or removed.
  • It starts the run loop so the notifications that have been set up will be received.

The main function uses I/O Kit functions to set up and modify a matching dictionary and set up notifications, and Core Foundation functions to set up the run loop for receiving the notifications. It calls the following functions to access both the raw device and the bulk test device.

  • RawDeviceAdded, shown in Listing 2-3, iterates over the set of matching devices and creates a device interface for each one. It calls ConfigureDevice (shown inListing 2-5) to set the device’s configuration, and then DownloadToDevice (shown in Listing 2-6) to download the firmware to program it.
  • RawDeviceRemoved, shown in Listing 2-4, iterates over the set of matching devices and releases each one in turn.
  • BulkTestDeviceAdded, shown in Listing 2-7, iterates over the new set of matching devices, creates a device interface for each one, and calls ConfigureDevice(shown in Listing 2-5) to set the device’s configuration. It then calls FindInterfaces (shown in Listing 2-8) to get access to the interfaces on the device.
  • BulkTestDeviceRemoved iterates over the new set of matching devices and releases each one in turn. This function is not shown in this chapter; seeRawDeviceRemoved (Listing 2-4) for a nearly identical function.

Listing 2-2  The main function

int main (int argc, const char *argv[])
{
    mach_port_t             masterPort;
    CFMutableDictionaryRef  matchingDict;
    CFRunLoopSourceRef      runLoopSource;
    kern_return_t           kr;
    SInt32                  usbVendor = kOurVendorID;
    SInt32                  usbProduct = kOurProductID;
    // Get command line arguments, if any
    if (argc > 1)
        usbVendor = atoi(argv[1]);
    if (argc > 2)
        usbProduct = atoi(argv[2]);
    //Create a master port for communication with the I/O Kit
    kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
    if (kr || !masterPort)
    {
        printf("ERR: Couldn’t create a master I/O Kit port(%08x)\n", kr);
        return -1;
    }
    //Set up matching dictionary for class IOUSBDevice and its subclasses
    matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
    if (!matchingDict)
    {
        printf("Couldn’t create a USB matching dictionary\n");
        mach_port_deallocate(mach_task_self(), masterPort);
        return -1;
    }
    //Add the vendor and product IDs to the matching dictionary.
    //This is the second key in the table of device-matching keys of the
    //USB Common Class Specification
    CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorName),
                        CFNumberCreate(kCFAllocatorDefault,
                                     kCFNumberSInt32Type, &usbVendor));
    CFDictionarySetValue(matchingDict, CFSTR(kUSBProductName),
                        CFNumberCreate(kCFAllocatorDefault,
                                    kCFNumberSInt32Type, &usbProduct));
    //To set up asynchronous notifications, create a notification port and
    //add its run loop event source to the program’s run loop
    gNotifyPort = IONotificationPortCreate(masterPort);
    runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                        kCFRunLoopDefaultMode);
    //Retain additional dictionary references because each call to
    //IOServiceAddMatchingNotification consumes one reference
    matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict);
    matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict);
    matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict);
    //Now set up two notifications: one to be called when a raw device
    //is first matched by the I/O Kit and another to be called when the
    //device is terminated
    //Notification of first match:
    kr = IOServiceAddMatchingNotification(gNotifyPort,
                    kIOFirstMatchNotification, matchingDict,
                    RawDeviceAdded, NULL, &gRawAddedIter);
    //Iterate over set of matching devices to access already-present devices
    //and to arm the notification
    RawDeviceAdded(NULL, gRawAddedIter);
    //Notification of termination:
    kr = IOServiceAddMatchingNotification(gNotifyPort,
                    kIOTerminatedNotification, matchingDict,
                    RawDeviceRemoved, NULL, &gRawRemovedIter);
    //Iterate over set of matching devices to release each one and to
    //arm the notification
    RawDeviceRemoved(NULL, gRawRemovedIter);
    //Now change the USB product ID in the matching dictionary to match
    //the one the device will have after the firmware has been downloaded
    usbProduct = kOurProductIDBulkTest;
    CFDictionarySetValue(matchingDict, CFSTR(kUSBProductName),
                        CFNumberCreate(kCFAllocatorDefault,
                                    kCFNumberSInt32Type, &usbProduct));
    //Now set up two notifications: one to be called when a bulk test device
    //is first matched by the I/O Kit and another to be called when the
    //device is terminated.
    //Notification of first match
    kr = IOServiceAddMatchingNotification(gNotifyPort,
                    kIOFirstMatchNotification, matchingDict,
                    BulkTestDeviceAdded, NULL, &gBulkTestAddedIter);
    //Iterate over set of matching devices to access already-present devices
    //and to arm the notification
    BulkTestDeviceAdded(NULL, gBulkTestAddedIter);
    //Notification of termination
    kr = IOServiceAddMatchingNotification(gNotifyPort,
                    kIOTerminatedNotification, matchingDict,
                    BulkTestDeviceRemoved, NULL, &gBulkTestRemovedIter);
    //Iterate over set of matching devices to release each one and to
    //arm the notification. NOTE: this function is not shown in this document.
    BulkTestDeviceRemoved(NULL, gBulkTestRemovedIter);
    //Finished with master port
    mach_port_deallocate(mach_task_self(), masterPort);
    masterPort = 0;
    //Start the run loop so notifications will be received
    CFRunLoopRun();
    //Because the run loop will run forever until interrupted,
    //the program should never reach this point
    return 0;
}

Working With the Raw Device

Now that you’ve obtained an iterator for a set of matching devices, you can use it to gain access to each raw device, configure it, and download the appropriate firmware to it. The function RawDeviceAdded (shown in Listing 2-3) uses I/O Kit functions to create a device interface for each device and then calls the following functions to configure the device and download firmware to it.

  • ConfigureDevice, shown in Listing 2-5, uses device interface functions to get the number of configurations, examine the first one, and set the device’s configuration.
  • DownloadToDevice, shown in Listing 2-6, downloads the firmware in bulktest.c to the device.

Listing 2-3  Accessing and programming the raw device

void RawDeviceAdded(void *refCon, io_iterator_t iterator)
{
    kern_return_t               kr;
    io_service_t                usbDevice;
    IOCFPlugInInterface         **plugInInterface = NULL;
    IOUSBDeviceInterface        **dev = NULL;
    HRESULT                     result;
    SInt32                      score;
    UInt16                      vendor;
    UInt16                      product;
    UInt16                      release;
    while (usbDevice = IOIteratorNext(iterator))
    {
        //Create an intermediate plug-in
        kr = IOCreatePlugInInterfaceForService(usbDevice,
                    kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
                    &plugInInterface, &score);
        //Don’t need the device object after intermediate plug-in is created
        kr = IOObjectRelease(usbDevice);
        if ((kIOReturnSuccess != kr) || !plugInInterface)
        {
            printf("Unable to create a plug-in (%08x)\n", kr);
            continue;
        }
        //Now create the device interface
        result = (*plugInInterface)->QueryInterface(plugInInterface,
                        CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
                        (LPVOID *)&dev);
        //Don’t need the intermediate plug-in after device interface
        //is created
        (*plugInInterface)->Release(plugInInterface);
        if (result || !dev)
        {
            printf("Couldn’t create a device interface (%08x)\n",
                                                    (int) result);
            continue;
        }
        //Check these values for confirmation
        kr = (*dev)->GetDeviceVendor(dev, &vendor);
        kr = (*dev)->GetDeviceProduct(dev, &product);
        kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
        if ((vendor != kOurVendorID) || (product != kOurProductID) ||
            (release != 1))
        {
            printf("Found unwanted device (vendor = %d, product = %d)\n",
                    vendor, product);
            (void) (*dev)->Release(dev);
            continue;
        }
        //Open the device to change its state
        kr = (*dev)->USBDeviceOpen(dev);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to open device: %08x\n", kr);
            (void) (*dev)->Release(dev);
            continue;
        }
        //Configure device
        kr = ConfigureDevice(dev);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to configure device: %08x\n", kr);
            (void) (*dev)->USBDeviceClose(dev);
            (void) (*dev)->Release(dev);
            continue;
        }
        //Download firmware to device
        kr = DownloadToDevice(dev);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to download firmware to device: %08x\n", kr);
            (void) (*dev)->USBDeviceClose(dev);
            (void) (*dev)->Release(dev);
            continue;
        }
        //Close this device and release object
        kr = (*dev)->USBDeviceClose(dev);
        kr = (*dev)->Release(dev);
    }
}

The function RawDeviceRemoved simply uses the iterator obtained from the main function (shown in Listing 2-2) to release each device object. This also has the effect of arming the raw device termination notification so it will notify the program of future device removals. RawDeviceRemoved is shown in Listing 2-4.

Listing 2-4  Releasing the raw device objects

void RawDeviceRemoved(void *refCon, io_iterator_t iterator)
{
    kern_return_t   kr;
    io_service_t    object;
    while (object = IOIteratorNext(iterator))
    {
        kr = IOObjectRelease(object);
        if (kr != kIOReturnSuccess)
        {
            printf("Couldn’t release raw device object: %08x\n", kr);
            continue;
        }
    }
}

Although every USB device has one or more configurations, unless the device is a composite class device that’s been matched by the AppleUSBComposite driver which automatically sets the first configuration, none of those configurations may have been set. Therefore, your application may have to use device interface functions to get the appropriate configuration value and use it to set the device’s configuration. In the sample code, the function ConfigureDevice (shown in Listing 2-5) accomplishes this task. In fact, it is called twice: once by RawDeviceAdded to configure the raw device and again by BulkTestDeviceAdded (shown in Listing 2-7) to configure the bulk test device.

Listing 2-5  Configuring a USB device

IOReturn ConfigureDevice(IOUSBDeviceInterface **dev)
{
    UInt8                           numConfig;
    IOReturn                        kr;
    IOUSBConfigurationDescriptorPtr configDesc;
    //Get the number of configurations. The sample code always chooses
    //the first configuration (at index 0) but your code may need a
    //different one
    kr = (*dev)->GetNumberOfConfigurations(dev, &numConfig);
    if (!numConfig)
        return -1;
    //Get the configuration descriptor for index 0
    kr = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &configDesc);
    if (kr)
    {
        printf("Couldn’t get configuration descriptor for index %d (err =
                %08x)\n", 0, kr);
        return -1;
    }
    //Set the device’s configuration. The configuration value is found in
    //the bConfigurationValue field of the configuration descriptor
    kr = (*dev)->SetConfiguration(dev, configDesc->bConfigurationValue);
    if (kr)
    {
        printf("Couldn’t set configuration to value %d (err = %08x)\n", 0,
                kr);
        return -1;
    }
    return kIOReturnSuccess;
}

Now that the device is configured, you can download firmware to it. Cypress makes firmware available to program the EZ-USB chip to emulate different devices. The sample code in this document uses firmware that programs the chip to be a bulk test device, a device that takes the data it receives from its bulk out pipe and echoes it to its bulk in pipe. The firmware, contained in the file bulktest.c, is an array of INTEL_HEX_RECORD structures (defined in the file hex2c.h).

The function DownloadToDevice uses the function WriteToDevice (shown together in Listing 2-6) to prepare the device to receive the download and then to write information from each structure to the appropriate address on the device. When all the firmware has been downloaded, DownloadToDevice calls WriteToDevice a last time to inform the device that the download is complete. At this point, the raw device detaches itself from the bus and reattaches as a bulk test device. This causes the device nub representing the raw device to be removed from the I/O Registry and a new device nub, representing the bulk test device, to be attached.

Listing 2-6  Two functions to download firmware to the raw device

IOReturn DownloadToDevice(IOUSBDeviceInterface **dev)
{
    int         i;
    UInt8       writeVal;
    IOReturn    kr;
    //Assert reset. This tells the device that the download is
    //about to occur
    writeVal = 1;   //For this device, a value of 1 indicates a download
    kr = WriteToDevice(dev, k8051_USBCS, 1, &writeVal);
    if (kr != kIOReturnSuccess)
    {
        printf("WriteToDevice reset returned err 0x%x\n", kr);
        (*dev)->USBDeviceClose(dev);
        (*dev)->Release(dev);
        return kr;
    }
    //Download firmware
    i = 0;
    while (bulktest[i].Type == 0)   //While bulktest[i].Type == 0, this is
    {                               //not the last firmware record to
                                    //download
        kr = WriteToDevice(dev, bulktest[i].Address,
                            bulktest[i].Length, bulktest[i].Data);
        if (kr != kIOReturnSuccess)
        {
            printf("WriteToDevice download %i returned err 0x%x\n", i,
                    kr);
            (*dev)->USBDeviceClose(dev);
            (*dev)->Release(dev);
            return kr;
        }
        i++;
    }
    //De-assert reset. This tells the device that the download is complete
    writeVal = 0;
    kr = WriteToDevice(dev, k8051_USBCS, 1, &writeVal);
    if (kr != kIOReturnSuccess)
        printf("WriteToDevice run returned err 0x%x\n", kr);
    return kr;
}
IOReturn WriteToDevice(IOUSBDeviceInterface **dev, UInt16 deviceAddress,
                        UInt16 length, UInt8 writeBuffer[])
{
    IOUSBDevRequest     request;
    request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor,
                                                kUSBDevice);
    request.bRequest = 0xa0;
    request.wValue = deviceAddress;
    request.wIndex = 0;
    request.wLength = length;
    request.pData = writeBuffer;
    return (*dev)->DeviceRequest(dev, &request);
}

Working With the Bulk Test Device

After you download the firmware to the device, the raw device is no longer attached to the bus. To gain access to the bulk test device, you repeat most of the same steps you used to get access to the raw device.

  • Use the iterator obtained by a call to IOServiceAddMatchingNotification in the main function (shown in Listing 2-2) to iterate over a set of matching devices.
  • Create a device interface for each device.
  • Configure the device.

This time, however, the next step is to find the interfaces on the device so you can choose the appropriate one and get access to its pipes. Because of the similarities of these tasks, the function BulkTestDeviceAdded follows the same outline of the RawDeviceAdded function except that instead of downloading firmware to the device, it calls FindInterfaces (shown in Listing 2-8) to examine the available interfaces and their pipes. The code in Listing 2-7 replaces most of theBulkTestDeviceAdded function’s code with comments, focusing on the differences between it and the RawDeviceAdded function.

Listing 2-7  Accessing the bulk test device

void BulkTestDeviceAdded(void *refCon, io_iterator_t iterator)
{
    kern_return_t           kr;
    io_service_t            usbDevice;
    IOUSBDeviceInterface    **device=NULL;
    while (usbDevice = IOIteratorNext(iterator))
    {
        //Create an intermediate plug-in using the
        //IOCreatePlugInInterfaceForService function
        //Release the device object after getting the intermediate plug-in
        //Create the device interface using the QueryInterface function
        //Release the intermediate plug-in object
        //Check the vendor, product, and release number values to
        //confirm we’ve got the right device
        //Open the device before configuring it
        kr = (*device)->USBDeviceOpen(device);
        //Configure the device by calling ConfigureDevice
        //Close the device and release the device interface object if
        //the configuration is unsuccessful
        //Get the interfaces
        kr = FindInterfaces(device);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to find interfaces on device: %08x\n", kr);
            (*device)->USBDeviceClose(device);
            (*device)->Release(device);
            continue;
        }
//If using synchronous IO, close and release the device interface here
#ifndef USB_ASYNC_IO
        kr = (*device)->USBDeviceClose(device);
        kr = (*device)->Release(device);
#endif
    }
}

The function BulkTestDeviceRemoved simply uses the iterator obtained from the main function (shown in Listing 2-2) to release each device object. This also has the effect of arming the bulk test device termination notification so it will notify the program of future device removals.The BulkTestDeviceRemoved function is identical to the RawDeviceRemoved function (shown in Listing 2-4), with the exception of the wording of the printed error statement.

Working With Interfaces

Now that you’ve configured the device, you have access to its interfaces. The FindInterfaces function (shown in Listing 2-8) creates an iterator to iterate over all interfaces on the device and then creates a device interface to communicate with each one. For each interface found, the function opens the interface, determines how many endpoints (or pipes) it has, and prints out the properties of each pipe. Because opening an interface causes its pipes to be instantiated, you can get access to any pipe by using its pipe index. The pipe index is the number of the pipe within the interface, ranging from one to the number of endpoints returned by GetNumEndpoints. You can communicate with the default control pipe (described in “USB Transfer Types”) from any interface by using pipe index 0, but it is usually better to use the device interface functions for the device itself (see the use of IOUSBDeviceInterface functions in Listing 2-5).

The sample code employs conditional compilation using #ifdef and #ifndef to demonstrate both synchronous and asynchronous I/O. If you’ve chosen to test synchronous I/O, FindInterfaces writes the test message (defined in Listing 2-1) to pipe index 2 on the device and reads its echo before returning. For asynchronous I/O, FindInterfaces first creates an event source and adds it to the run loop created by the main function (shown in Listing 2-2). It then sets up an asynchronous write and read that will cause a notification to be sent upon completion. The completion functions WriteCompletion and ReadCompletion are shown together inListing 2-9.

Listing 2-8  Finding interfaces on the bulk test device

IOReturn FindInterfaces(IOUSBDeviceInterface **device)
{
    IOReturn                    kr;
    IOUSBFindInterfaceRequest   request;
    io_iterator_t               iterator;
    io_service_t                usbInterface;
    IOCFPlugInInterface         **plugInInterface = NULL;
    IOUSBInterfaceInterface     **interface = NULL;
    HRESULT                     result;
    SInt32                      score;
    UInt8                       interfaceClass;
    UInt8                       interfaceSubClass;
    UInt8                       interfaceNumEndpoints;
    int                         pipeRef;
#ifndef USE_ASYNC_IO
    UInt32                      numBytesRead;
    UInt32                      i;
#else
    CFRunLoopSourceRef          runLoopSource;
#endif
    //Placing the constant kIOUSBFindInterfaceDontCare into the following
    //fields of the IOUSBFindInterfaceRequest structure will allow you
    //to find all the interfaces
    request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
    request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
    request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
    request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
    //Get an iterator for the interfaces on the device
    kr = (*device)->CreateInterfaceIterator(device,
                                        &request, &iterator);
    while (usbInterface = IOIteratorNext(iterator))
    {
        //Create an intermediate plug-in
        kr = IOCreatePlugInInterfaceForService(usbInterface,
                            kIOUSBInterfaceUserClientTypeID,
                            kIOCFPlugInInterfaceID,
                            &plugInInterface, &score);
        //Release the usbInterface object after getting the plug-in
        kr = IOObjectRelease(usbInterface);
        if ((kr != kIOReturnSuccess) || !plugInInterface)
        {
            printf("Unable to create a plug-in (%08x)\n", kr);
            break;
        }
        //Now create the device interface for the interface
        result = (*plugInInterface)->QueryInterface(plugInInterface,
                    CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
                    (LPVOID *) &interface);
        //No longer need the intermediate plug-in
        (*plugInInterface)->Release(plugInInterface);
        if (result || !interface)
        {
            printf("Couldn’t create a device interface for the interface
                    (%08x)\n", (int) result);
            break;
        }
        //Get interface class and subclass
        kr = (*interface)->GetInterfaceClass(interface,
                                                    &interfaceClass);
        kr = (*interface)->GetInterfaceSubClass(interface,
                                                &interfaceSubClass);
        printf("Interface class %d, subclass %d\n", interfaceClass,
                                                    interfaceSubClass);
        //Now open the interface. This will cause the pipes associated with
        //the endpoints in the interface descriptor to be instantiated
        kr = (*interface)->USBInterfaceOpen(interface);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to open interface (%08x)\n", kr);
            (void) (*interface)->Release(interface);
            break;
        }
        //Get the number of endpoints associated with this interface
        kr = (*interface)->GetNumEndpoints(interface,
                                        &interfaceNumEndpoints);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to get number of endpoints (%08x)\n", kr);
            (void) (*interface)->USBInterfaceClose(interface);
            (void) (*interface)->Release(interface);
            break;
        }
        printf("Interface has %d endpoints\n", interfaceNumEndpoints);
        //Access each pipe in turn, starting with the pipe at index 1
        //The pipe at index 0 is the default control pipe and should be
        //accessed using (*usbDevice)->DeviceRequest() instead
        for (pipeRef = 1; pipeRef <= interfaceNumEndpoints; pipeRef++)
        {
            IOReturn        kr2;
            UInt8           direction;
            UInt8           number;
            UInt8           transferType;
            UInt16          maxPacketSize;
            UInt8           interval;
            char            *message;
            kr2 = (*interface)->GetPipeProperties(interface,
                                        pipeRef, &direction,
                                        &number, &transferType,
                                        &maxPacketSize, &interval);
            if (kr2 != kIOReturnSuccess)
                printf("Unable to get properties of pipe %d (%08x)\n",
                                        pipeRef, kr2);
            else
            {
                printf("PipeRef %d: ", pipeRef);
                switch (direction)
                {
                    case kUSBOut:
                        message = "out";
                        break;
                    case kUSBIn:
                        message = "in";
                        break;
                    case kUSBNone:
                        message = "none";
                        break;
                    case kUSBAnyDirn:
                        message = "any";
                        break;
                    default:
                        message = "???";
                }
                printf("direction %s, ", message);
                switch (transferType)
                {
                    case kUSBControl:
                        message = "control";
                        break;
                    case kUSBIsoc:
                        message = "isoc";
                        break;
                    case kUSBBulk:
                        message = "bulk";
                        break;
                    case kUSBInterrupt:
                        message = "interrupt";
                        break;
                    case kUSBAnyType:
                        message = "any";
                        break;
                    default:
                        message = "???";
                }
                printf("transfer type %s, maxPacketSize %d\n", message,
                                                    maxPacketSize);
            }
        }
#ifndef USE_ASYNC_IO    //Demonstrate synchronous I/O
        kr = (*interface)->WritePipe(interface, 2, kTestMessage,
                                            strlen(kTestMessage));
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to perform bulk write (%08x)\n", kr);
            (void) (*interface)->USBInterfaceClose(interface);
            (void) (*interface)->Release(interface);
            break;
        }
        printf("Wrote \"%s\" (%ld bytes) to bulk endpoint\n", kTestMessage,
                                        (UInt32) strlen(kTestMessage));
        numBytesRead = sizeof(gBuffer) - 1; //leave one byte at the end
                                             //for NULL termination
        kr = (*interface)->ReadPipe(interface, 9, gBuffer,
                                            &numBytesRead);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to perform bulk read (%08x)\n", kr);
            (void) (*interface)->USBInterfaceClose(interface);
            (void) (*interface)->Release(interface);
            break;
        }
        //Because the downloaded firmware echoes the one’s complement of the
        //message, now complement the buffer contents to get the original data
        for (i = 0; i < numBytesRead; i++)
            gBuffer[i] = ~gBuffer[i];
        printf("Read \"%s\" (%ld bytes) from bulk endpoint\n", gBuffer,
                    numBytesRead);
#else   //Demonstrate asynchronous I/O
        //As with service matching notifications, to receive asynchronous
        //I/O completion notifications, you must create an event source and
        //add it to the run loop
        kr = (*interface)->CreateInterfaceAsyncEventSource(
                                    interface, &runLoopSource);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to create asynchronous event source
                                    (%08x)\n", kr);
            (void) (*interface)->USBInterfaceClose(interface);
            (void) (*interface)->Release(interface);
            break;
        }
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                            kCFRunLoopDefaultMode);
        printf("Asynchronous event source added to run loop\n");
        bzero(gBuffer, sizeof(gBuffer));
        strcpy(gBuffer, kTestMessage);
        kr = (*interface)->WritePipeAsync(interface, 2, gBuffer,
                                    strlen(gBuffer),
                                    WriteCompletion, (void *) interface);
        if (kr != kIOReturnSuccess)
        {
            printf("Unable to perform asynchronous bulk write (%08x)\n",
                                                    kr);
            (void) (*interface)->USBInterfaceClose(interface);
            (void) (*interface)->Release(interface);
            break;
        }
#endif
        //For this test, just use first interface, so exit loop
        break;
    }
    return kr;
}

When an asynchronous write action is complete, the WriteCompletion function is called by the notification. WriteCompletion then calls the interface functionReadPipeAsync to perform an asynchronous read from the pipe. When the read is complete, control passes to ReadCompletion which simply prints status messages and adds a NULL termination to the global buffer containing the test message read from the device. The WriteCompletion and ReadCompletion functions are shown together in Listing 2-9.

Listing 2-9  Two asynchronous I/O completion functions

void WriteCompletion(void *refCon, IOReturn result, void *arg0)
{
    IOUSBInterfaceInterface **interface = (IOUSBInterfaceInterface **) refCon;
    UInt32                  numBytesWritten = (UInt32) arg0;
    UInt32                  numBytesRead;
    printf("Asynchronous write complete\n");
    if (result != kIOReturnSuccess)
    {
        printf("error from asynchronous bulk write (%08x)\n", result);
        (void) (*interface)->USBInterfaceClose(interface);
        (void) (*interface)->Release(interface);
        return;
    }
    printf("Wrote \"%s\" (%ld bytes) to bulk endpoint\n", kTestMessage,
                                        numBytesWritten);
    numBytesRead = sizeof(gBuffer) - 1; //leave one byte at the end for
                                            //NULL termination
    result = (*interface)->ReadPipeAsync(interface, 9, gBuffer,
                                    numBytesRead, ReadCompletion, refCon);
    if (result != kIOReturnSuccess)
    {
        printf("Unable to perform asynchronous bulk read (%08x)\n", result);
        (void) (*interface)->USBInterfaceClose(interface);
        (void) (*interface)->Release(interface);
        return;
    }
}
void ReadCompletion(void *refCon, IOReturn result, void *arg0)
{
    IOUSBInterfaceInterface **interface = (IOUSBInterfaceInterface **) refCon;
    UInt32      numBytesRead = (UInt32) arg0;
    UInt32      i;
    printf("Asynchronous bulk read complete\n");
    if (result != kIOReturnSuccess) {
        printf("error from async bulk read (%08x)\n", result);
        (void) (*interface)->USBInterfaceClose(interface);
        (void) (*interface)->Release(interface);
        return;
    }
    //Check the complement of the buffer’s contents for original data
    for (i = 0; i < numBytesRead; i++)
        gBuffer[i] = ~gBuffer[i];
    printf("Read \"%s\" (%ld bytes) from bulk endpoint\n", gBuffer,
                                                    numBytesRead);
}

iPhone开发:如何直接用Object-C连接数据库

iphone开发连数据库一般有两种

1.core data 这种是可视化的存储方式,不带sql语句的,应该是官方封装好了
2.直接通过sql语句连接sqlite:
[code lang="c"]
- (BOOL) databaseTest
{
//数据库操作
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"mydb.db"];//查找db文件返回其path
NSLog(path);//打印db文件的路径
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL find = [fileManager fileExistsAtPath:path];
if(find){
NSLog(@"Sucess:find dn file.");
if(sqlite3_open([path UTF8String], &database_) == SQLITE_OK)//打开数据库
{

//打开数据库成功
NSLog(@"Sucess:open database sucess.");
/////////////////////////////////////////////////////////////////////////////////
//这里进行数据库操作
/////////////////////////////////////////////////////////////////////////////////
//////////////////////////1.插入数据////////////////////////////////////////////////
//SQL查询语句
char *sql = "INSERT INTO students (name) VALUES(?)";
//会话
sqlite3_stmt *statement;
//调制一个会话
int success = sqlite3_prepare_v2(database_, sql, -1, &statement, NULL);
if (success != SQLITE_OK) {
NSLog(@"Error: failed to insert:channels");
}
//绑定数据

sqlite3_bind_text(statement, 1, "Kevin", -1, SQLITE_TRANSIENT);//注意此处的字符串为旧字符串
success = sqlite3_step(statement);
sqlite3_finalize(statement);
if (success == SQLITE_ERROR) {
NSLog(@"Error: failed to insert into the database with message.");
}

//2.查询数据
statement = nil;
char *sql_select= "SELECT name FROM students";
if (sqlite3_prepare_v2(database_, sql_select, -1, &statement, NULL) != SQLITE_OK) {
NSLog(@"Error: failed to prepare statement with message:get channels.");
}
//查询结果集中一条一条的遍历所有的记录,这里的数字对应的是列值。
while (sqlite3_step(statement) == SQLITE_ROW) {
char* name = (char*) sqlite3_column_text(statement, 0);//第一列数据,注意此处师从0开始的
NSString *nameNs=[[NSString alloc] initWithUTF8String:name];
NSLog(nameNs);
[nameNs release];

}
sqlite3_finalize(statement);

//关闭数据库
sqlite3_close(database_);
return YES;
}
else
{
sqlite3_close(database_);
NSLog(@"Error: open database file.");
return NO;
}

return NO;
}
}
[/code]

iPhone4S刚刚发布,iFixit即宣布拆解完成

iFixit一直因为拆解、披露苹果设备组件而闻名。

iPhone 4S还采用A5片上系统(System-on-a-Chip),频率为1GHz,配512MB DDR2内存,后置800万像素摄像头,可以捕捉1080p视频,前置VGA摄像头。装备有802.11 b/g/n,蓝牙4.0。显示屏为LED背光IPS TFT LCD Retina 屏,分辨率960X640。手机支持GSM、GPRS、EDGE、WCDMA网络。