标签归档:iPhone

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。

 

 

用xcode 5 开发访问IOS 7上面的通讯录问题

NSMutableArray *addressBookTemp = [NSMutableArray array];ABAddressBookRef addressBooks = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBooks);

CFIndex nPeople = ABAddressBookGetPersonCount(addressBooks);

 

 

这段代码在IOS6是可以读取通讯录的,但在IOS7下面就不行,程序没报错,调试时候发现返回的都是nil,有木有朋友遇到这个问题?

找到原因了,原来IOS7需要隐私验证,调用通讯录里面API需要以下代码作为权限认证:

 __block BOOL accessGranted = NO;
 if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
  ABAddressBookRequestAccessWithCompletion(addressBooks, ^(bool granted, CFErrorRef error)
 {
   // First time access has been granted, add the contact 
   accessGranted = granted; });
 }
 else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
 {
  // The user has previously given access, add the contact 
  accessGranted = YES;
 }
 else
 {
 // The user has previously denied access
 // Send an alert telling user to change privacy setting in settings app
 }

不过IOS6好像没有,希望对其他朋友有帮助 – sfdux 2013-09-24 11:12 回复

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

 

再来说说iPhone接收彩信的配置

之前找了好多教程啊啥的都配置不成功,用了一年多iPhone,始终没能接收和发送彩信。

今天再次找了篇文章,按照所说的参数配置完成,果然收到彩信了,既郁闷又兴奋。

下面再说说iPhone3GS的配置过程。

第一、从设置->通用里进入“网络”

 

打开“蜂窝数据”,进入“蜂窝数据网络”:

 

“蜂窝数据”中的APN一定要填cmnet,其他空着:

 

“彩信”中的“APN”一定要写“cmwap”、“MMSC”为“http://mmsc.monternet.com”,记得必须加“http://”,“彩信代理”写“10.0.0.72”,没必要加80端口号!“最大的彩信大小”设置成50000足够了。其他不用管。

第二、返回到“设置”,找到“短信”栏

 

进入后如下设置即可:

记得设置完后必须重启,我尝试进入飞行模式然后重新取消飞行默认来重置网络,似乎不起作用。

 

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开发-UITableView详细讲解(转)

-、建立 UITableView

[code lang=”c”]

 DataTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 420)];
 [DataTable setDelegate:self];
 [DataTable setDataSource:self];
 [self.view addSubview:DataTable];
 [DataTable release];

[/code]

二、UITableView各Method说明

[code lang=”c”]
//Section总数
– (NSArray *)sectionIndexTitlesForTab leView:(UITableView *)tableView{
 return TitleData;
}

// Section Titles
//每个section显示的标题
– (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
 return @"";
}
//指定有多少个分区(Section),默认为1
– (NSInteger)numberOfSectionsInTableV iew:(UITableView *)tableView {
 return 4;
}
//指定每个分区中有多少行,默认为1
– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
}
//绘制Cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";

   UITableViewCell *cell = [tableView dequeueReusableCellWithI dentifier:
                            SimpleTableIdentifier];
   if (cell == nil) {
       cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefa ult
                                      reuseIdentifier: SimpleTableIdentifier] autorelease];
 }
 cell.imageView.image=image;//未选cell时的图片
 cell.imageView.highlightedImage=highlightImage;//选中cell后的图片
 cell.text=//…..
 return cell;
}
//行缩进
-(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAt IndexPath:(NSIndexPath *)indexPath{
 NSUInteger row = [indexPath row];
 return row;
}
//改变行的高度
– (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
   return 40;
}
//定位
[TopicsTable setContentOffset:CGPointMake(0, promiseNum * 44 + Chapter * 20)];
//返回当前所选cell
NSIndexPath *ip = [NSIndexPath indexPathForRow:row inSection:section];
[TopicsTable selectRowAtIndexPath:ip animated:YES scrollPosition:UITableViewScrollPositio nNone];
[tableView setSeparatorStyle:UITableViewCellSelection StyleNone];
//选中Cell响应事件
– (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

 [tableView deselectRowAtIndexPath:indexPath animated:YES];//选中后的反显颜色即刻消失
}
//判断选中的行(阻止选中第一行)
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath :(NSIndexPath *)indexPath
{
   NSUInteger row = [indexPath row];
   if (row == 0)
       return nil;

   return indexPath;
}
//划动cell是否出现del按钮
– (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
}
//编辑状态
– (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingSt yle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{

[topicsTable setContentSize:CGSizeMake(0,controller.promiseNum * 44)];
//右侧添加一个索引表
– (NSArray *)sectionIndexTitlesForTab leView:(UITableView *)tableView{
}

//返回Section标题内容
– (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
}

//自定义划动时del按钮内容
– (NSString *)tableView:(UITableView *)tableView
titleForDeleteConfirmati onButtonForRowAtIndexPat h:(NSIndexPath *)indexPath
//跳到指的row or section
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositio nBottom animated:NO];

[/code]

三、在UITableViewCell上建立UILable多行显示

[code lang=”c”]

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   static NSString *CellIdentifier = @"Cell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithI dentifier:CellIdentifier];
   if (cell == nil) {
       cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
  UILabel *Datalabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 320, 44)];
  [Datalabel setTag:100];
  Datalabel.autoresizingMask = UIViewAutoresizingFlexib leWidth | UIViewAutoresizingFlexib leHeight;
  [cell.contentView addSubview:Datalabel];
  [Datalabel release];
 }
 UILabel *Datalabel = (UILabel *)[cell.contentView viewWithTag:100];
 [Datalabel setFont:[UIFont boldSystemFontOfSize:18]];
 Datalabel.text = [data.DataArray objectAtIndex:indexPath.row];
 cell.accessoryType = UITableViewCellAccessory DisclosureIndicator;
   return cell;
}

//选中cell时的颜色

typedef enum {
   UITableViewCellSelection StyleNone,
   UITableViewCellSelection StyleBlue,
   UITableViewCellSelection StyleGray
} UITableViewCellSelection Style

//cell右边按钮格式

typedef enum {
   UITableViewCellAccessory None,                   // don’t show any accessory view
   UITableViewCellAccessory DisclosureIndicator,    // regular chevron. doesn’t track
   UITableViewCellAccessory DetailDisclosureButton, // blue button w/ chevron. tracks
   UITableViewCellAccessory Checkmark               // checkmark. doesn’t track
} UITableViewCellAccessory Type //是否加换行线

typedef enum {
   UITableViewCellSeparator StyleNone,
   UITableViewCellSeparator StyleSingleLine
} UITableViewCellSeparator Style//改变换行线颜色

tableView.separatorColor = [UIColor blueColor];

[/code]

本文转自:http://zyc-to.blog.163.com/blog/static/171524002010112831630425/

iPhone Application Post Build Script

很多平台软件开发发布前, 有个很重要的事情就是保留好符号表(symbol)文件. 因为发布的软件一般来说都去除了符号表, 而符号表对于维护是很重要的信息, 没有它, 在拿到call stack后会很难对应到代码中. iPhone开发也是一样, 每次做完Build, 都会有一个.dSYM的目录, 就是符号表. 有了它, 在用户提交crash log后会很容易定位问题.

 

手工保存这些符号表文件很容易产生疏漏, 恢复起来又麻烦. 我做了一个脚本, 添加到Target的Run Script Build Phase中, 可以在Build类型是Distribution时, 将build出的binary和符号表分别打包为:

  • [application].app.[version].zip
  • [application].app.dSYM.[version].[git hash].zip

如果你用的版本管理系统不是git,需要对脚本做相应改动.
以下是脚本代码

 

[code lang=”shell”]
<div>
<div>
<pre>#!/usr/bin/env ruby
if ENV["BUILD_STYLE"] == "Distribution" && ENV["ARCHS"] == ‘armv6’
common_git_paths = %w[/usr/local/bin/git /usr/local/git/bin/git /opt/local/bin/git]
git_path = ""

common_git_paths.each do |p|
if File.exist?(p)
git_path = p
break
end
end

if git_path == ""
puts "Path to git not found"
exit
end

command_line = git_path + " rev-parse –short HEAD"
sha = `#{command_line}`.chomp

info_file = ENV[‘INFOPLIST_FILE’]

f = File.open(info_file, "r").read
re = /([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>)(.*?)(<\/string>)/
f =~ re
puts $1

# Get the version info from the source Info.plist file
# If the script has already been run we need to remove the git sha
# from the bundle’s Info.plist.
version = $2.sub(/ \([\w]+\)/, "")

cmdline = "cd #{ENV[‘BUILT_PRODUCTS_DIR’]};zip -r #{ENV[‘CONTENTS_FOLDER_PATH’]}.#{version}.zip #{ENV[‘CONTENTS_FOLDER_PATH’]};zip -r #{ENV[‘CONTENTS_FOLDER_PATH’]}.dSYM.#{version}.#{sha}.zip #{ENV[‘CONTENTS_FOLDER_PATH’]}.dSYM"
`#{cmdline}`
end

[/code]