分类目录归档:iPhone

在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! :)

 

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就解决这个问题了。
  如果你不想升级固件,在输入手机号后按一下键盘上的“回行”就不会截断号码了。

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网络。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

乔布斯生平

乔布斯1955年2月24日生于旧金山。母亲乔安·卡罗尔-席博(Joanne Carole Schieble)和叙利亚裔父亲阿卜杜勒法塔赫-江达利(Abdulfattah Jandali)当时尚未结婚。克拉拉·乔布斯和保罗·乔布斯收养了乔布斯,这是一个家境并不宽裕的美国中产阶级家庭。1972年,乔布斯从美国加州库比提诺市Homestead高级中学(Homestead High School)毕业,同时被俄勒冈瑞德学院 (Reed College )录取。

一个学期后,乔布斯辍学了,并在1976年4月份与一道辍学的斯蒂夫·盖瑞-沃兹尼亚克(Stephen Gary Wozniak)在自己的车库中创建了苹果电脑。当时,21岁的乔布斯担任销售员的角色,而沃兹尼亚克则是工程师。选择“苹果电脑”这一名称,部分的缘由是披头士乐队,因为乔布斯是披头士的粉丝,崇拜该乐队的苹果唱片公司。

1977年,乔布斯和沃兹尼亚克推出了Apple II–第一款成功的个人电脑。其目的是面向大众市场,而不再是给工程师或爱好者提供的工具。它很大程度上仍是来自沃兹尼亚克的设计。该模型几经升级,产品线一直延续到了1993年。在1980年苹果电脑进行首次公开招股时,Apple II已经能够给公司带来1.17亿美元的年营收。通过公司的首次公开招股,乔布斯也成为了一名百万富豪。

并不是乔布斯所有的初期想法都能取得成效。在1980年推出的Apple III和1983年推出的Lisa就曾兵败滑铁卢。但是与众不同的一体机Macintosh,真正创建了现代计算机操作系统的标准,用户可以手动鼠标点击图标,而不再是输入命令符。

即使那样,乔布斯在设计细节上依然坚持己见。1978年加入苹果的前用户界面专家布鲁斯·托格纳兹尼(Bruce Tognazzini)曾回忆说,乔布斯曾坚持认为,键盘不应当包括“上、下、左、右”键,应当让用户移动鼠标了操控计算机屏幕。

乔布斯对美学的追求有事会走向极端。在上世纪80年代和1998年至2005年曾担任苹果工程师的乔治·克劳(George Crow)回忆说,乔布斯甚至会要求计算机内部非常美观。在推出首款Macintosh时,乔布斯要求机箱内的内部线路的颜色与苹果早期的彩虹标识一致。克劳说,他最终让乔布斯信服,这些是不必要的浪费。

Macintosh的设计,很大程度上来自于乔布斯1979年在参观施乐位于帕洛阿尔托实验室时,看到的Xerox Alto拥有的粗糙的用户界面和鼠标。这台计算机和当时的计算机没有任何相似之处,仿佛是未来的人们设计的。它配备了图形化的界面、用鼠标进行操作、配有文字和图像处理程序、并且连上了以太网。乔布斯在上世纪90年代中期美国公共广播公司(PBS)的节目中曾表示,“毕加索曾经说过,‘优秀的艺术家复制,伟大的艺术家剽窃。’我一直无耻的剽窃了伟大的创意。”

即便是在穿着打扮上,乔布斯也更像是一位艺术家而不是企业高管。在公众场合,乔布斯几乎一直穿着李维斯牛仔裤、黑色圆领衫和New Balance跑鞋。

随着苹果的不断扩张,乔布斯决定聘用一名更富有经验的管理者来执掌公司。1983年,乔布斯将百事可乐高管约翰·斯卡利招至麾下,没想到却为自己埋下了隐患。由于二人意见分歧,斯卡利后来占据了上风,导致乔布斯1985年被驱逐。在挖来斯库利的过程中,乔布斯说出了也许是他一生中最具说服力的话,“你想一辈子卖糖水,还是改变整个世界?”

在被苹果驱逐之后,乔布斯创建了一家新公司NeXT计算机,主要开发工作站。有“互联网之父”美誉的蒂姆·伯纳斯-李(Tim Berners-Lee)最初就是在一台NeXT工作站上创建了最早的网站。NeXT最终销售硬件,但后来停止了硬件销售。但是作为一家软件公司,NeXT并未赚到太多的钱。但是该公司的操作系统成为了OS X操作系统的前身。1996年12月,苹果宣布4亿美元收购NeXT,标志着乔布斯的回归。

早在1986年,乔布斯使用他自己的资金,斥资1000万美元从著名制片人、《星球大战》的导演乔治·卢卡斯(George Lucas)的手中买下了Lucasfilm的计算机绘图部门。该公司包括了皮克斯动画工作室,最初曾卖过硬件,也卖过软件,最后才成为了一家动画工作室。皮克斯动画工作室推出了《玩具总动员》等一系列绘制人口的动画片。2006年1月,乔布斯以74亿美元的价格将皮克斯动画工作室出售给沃尔特迪士尼。这一交易不仅上乔布斯成为沃尔特迪士尼的最大股东,而且还获得了该公司董事会的一个席位。

就在这一时期,苹果开始沉沦。使用英特尔处理器和微软操作系统的PC开始统治市场,在微软的Windows操作系统开始借助Macintosh虚拟界面的许多元素之后,这一趋势更是开始加剧。

与微软不同,苹果在这时需要同时资助公司内部的硬件和软件开发。由于几乎没有应用开发者为Macintosh开发应用,苹果最终决定把自己的操作系统向其它硬件厂商授权,但是这一决定太晚,已经于事无补。

在1997年时,苹果在过去两年中已经亏损了20亿美元左右,该公司股价接连创出历史新低。当时,带领苹果的是公司第三任首席执行官吉尔·阿梅里奥(Gil Amelio)。在2006年12月收购NeXT之后,苹果董事会决定解雇阿梅里奥 ,并让乔布斯回到苹果董事会就任特别顾问,同时他们也在紧锣密鼓地寻找新首席执行官的最佳人选。此后接下来的3个月里,乔布斯一直监管着董事会的动态,并否决了公司的操作系统复制许可项目,并与微软达成了一项划时代的交易合作计划。这些只能由乔布斯主导所采取的举措,最后证明对苹果的生存起到了至关重要的作用。1997年9月,苹果董事会终于再度任命史蒂夫为首席执行官。

在重新担任苹果首席执行官之后,乔布斯只拿着1美元的年薪和公司的股票期权,做出了一系列快速产生结果的变革。乔布斯终止了带来Mac克隆机的软件授权项目,取消了陷入困境的Newton掌上电脑,并决定让Mac专注于企业市场。

1998年5月,苹果在乔布斯的带领下推出了iMac。这一产品的推出,迫使竞争对手纷纷对自己的产品设计进行改进。在乔布斯的带领下,苹果发起了“Think Different”广告活动。在苹果股东对公司变化感到欣喜的情况下,乔布斯在苹果的地位进一步得到了巩固。在接管苹果的数月时间里,乔布斯用前NeXT党羽替换了苹果5位高管中的4位。他还发布内部电子邮件,禁止总部员工悠闲的带着宠物来到办公室,禁止在停车场抽烟,而且警告泄露公司机密文件的员工一定会被开除。

在乔布斯重新返回苹果后,苹果也曾犯下了一些错误,其中包括推出立方体的Macintosh,由于无法在市场中流行,苹果在2001年撤下了该项目。这一产品的失败也导致苹果当季业绩出现亏损,并警告在2000年和2001年数个季度无法实现业绩预期。

但是在此之后,苹果推出了一系列伟大的产品。2001年,苹果推出了钛金属外壳的PowerBook笔记本电脑,这种金属经常在战斗机中使用。同年,苹果推出了改变数字音乐产业的iPod音乐播放器。到2010年9月,苹果已累计售出了2.75亿部iPod,占据了全球音乐播放器市场超过70%的份额。

2003年,苹果推出了iTunes音乐商店。当时,音乐产业与数字革新还没有任何的联系,虽然受到了非法下载产业的重创,但是仍不愿意轻松、便宜的在网上销售歌曲。但是乔布斯说服了主要唱片商,销售每首99美分的歌曲,以及对盗版的限制,能够让绝大多数的消费者所接受。

已经销售出超过100亿首歌曲的iTunes,在2008年成为美国最大的音乐零售商。iTunes的成功,也刺激着消费者去购买iPod。因为在iTunes创办至今的绝大多数时间里,来自iTunes的歌曲只能够被下载到苹果的音乐播放器当中,其它厂商的设备无法从iTunes下载歌曲。

就在这一时期,乔布斯也在打造自己的管理团队。他在上世纪90年代末招募了前康柏计算机高管蒂姆·库克(Tim Cook),来加强苹果的运营,随后又把库克提升为首席运营官。2000年,乔布斯从零售商塔吉特挖来了罗恩·约翰逊(Ron Johnson),让其担任苹果零售业务高级副总裁,并开始在全球开设苹果零售店。苹果首席设计师乔纳森·艾夫(Jonathan Ive)则负责公司产品的设计工作,因为他与乔布斯在产品设计上有着类似的感悟力。

2004年,乔布斯突然因病从公司短暂离职。后来乔布斯披露说,离职期间他接受了胰腺癌手术治疗。不过当时便有消息人士透露,乔布斯早在9个月之前便已经知道了自己患病的情况。而在这一段时期内,苹果董事会及乔布斯均对苹果股东未透露任何消息。

当乔布斯最初确诊为癌症时,医生认为他已经时日无多。但是,他从未被病魔吓倒,一直保持着健康人的工作状态和心情。

2007年,苹果推出iPhone让乔布斯再次走上神坛。也正是iPhone手机,让整个手机产业经历了一场巨变。消息人士透露,乔布斯亲自参与了iPhone手机的整个设计过程,而且乔布斯也是把iPhone频幕从塑料转变为玻璃的关键人物之一。从开始测试iPhone频幕至产品发布,仅仅用了7个月的时间。尽管在进入智能手机市场之初,曾有人对苹果的能力产生过怀疑,但是事实证明,这种怀疑无疑是杞人忧天。市场调研公司IDC的统计数据显示,今年第二季度,苹果已成为了全球最大的智能手机制造商。

去年,乔布斯还推出了iPad平板电脑。在这款产品发布的前9个月时间里,苹果销售出了1480万部iPad。据接近乔布斯的苹果工作人员透露,iPad项目对乔布斯非常重要,即便是刚从2009年的肝脏移植手术中恢复,乔布斯还是私下参与了iPad的开发工作。

iPad和iPhone的一大卖点是苹果应用商店(App Store)。截至2010年7月底,苹果应用商店的应用下载总数突破了70亿次。

乔布斯的任职履历上也有过污点。2006年年中以来,美国证券市场爆发了大规模“期权股权倒签丑闻”,上市公司通常授予高管股票期权作为提高公司业绩表现和股价激励机制,但许多上市公司管理层凭借操纵股票期权回溯日期,刻意挑选股价较低水平时作为期权授予日,以扩大获利空间,所带来的差价利润通常是几千万到上亿美元。2006年6月,苹果经内部调查发现,1997年至2001年间的部分股票期权发放存在问题,有6400多份股权日期错填,为此需额外计入8400万美元支出。不过苹果否认乔布斯因“股权倒签”受益。

熟悉乔布斯的人透露,乔布斯之所以能够保持创新,是因为他不会迷恋过去的成绩,持续关注并要求员工也是如此。乔布斯2005年在斯坦福大学的学生毕业典礼上说:“死亡可能是生命的最佳创新,因为它将彻底改变你的生命。死亡让老人消失,从而为年轻人让路。现在你们是年轻人,但未来会逐步变为老人并消失。也许我的讲话过于戏剧性,但这是事实。”

在乔布斯超过30年的职业生涯中,他帮助硅谷这一气氛慵懒的农村地区变为科技行业的创新中心。除与微软联合创始人比尔·盖茨(Bill Gates)、甲骨文创始人拉里·埃里森(Larry Ellison)等产业先驱为现代高科技产业顶顶了基础之外,乔布斯还向世人证明,设计精巧的感官产品的感染力超过了技术力量的本身,并在一个越来越数字化的世界中,改变了消费者与技术互动的方式。

但是与那些人不同,乔布斯最大的创造力出现在生命的最后阶段,当几乎一系列完整的创新和取得巨大成功的产品,如iPod、iPhone和iPad极大的改变了PC、电子和数字媒体产品。与此同时,乔布斯通过具有魅力的广告宣传和自有零售店推广和销售这些产品,让苹果成为了流行文化的图标。

在这一阶段开始之时,乔布斯曾描述自己的理念是让产品“成为艺术和技术的结合体”。按照这一理念,乔布斯把苹果变成了全球市值最高的公司。

在乔布斯的人生最后时刻,他的妻子劳伦(Laurene),以及四位子女陪他一起度过。

乔布斯不仅在科技产业取得了巨大的成就,而且在娱乐产业也取得了突破性的成绩。他把苹果转变成为了全球最大的音乐零售商,而且作为皮克斯动画工作室的首席执行官和投资家,他协助了计算机动画电影的流行。后来,他把皮克斯动画工作室出售给了沃尔特迪士尼公司。乔布斯是改变了人们使用互联网,收听音乐,观看电视、电影,阅读图书的关键人物,并逐步的瓦解了各个产业。

在现代商业史中,乔布斯回归苹果留下了最光辉的一页。在离开苹果11年并重返这家公司之后,乔布斯带领着这家濒临破产的公司推出了iMac一体电脑、iPod音乐播放器和iTunes音乐商店。

苹果当前的年营收达到652亿美元,远超过1997财年(截至1997年9月末)的71亿美元。苹果已成为了全球首屈一指的消费电子设备设计厂商,并在2007年1月将名称中的“电脑”(苹果原名为苹果电脑,即Apple Computer)一词去除,以强调公司向PC之外的业务进行扩张。

尽管乔布斯在今年8月把公司帅印正式交付给他长期的助手蒂姆·库克(Tim Cook),但是他的逝世还是会引发一系列的质疑,在没有乔布斯的眼光和指引下,苹果如何能够延续自己的成功。在过去的十年当中,苹果已成为了全球技术创新力的排头兵。美国资本主义的其它一些标志性企业,如沃尔特迪士尼、沃尔玛、IBM等公司,也曾经历了转型之痛,但是在他们具有超凡魅力的创始人退位之后,都最终生存了下来。

但是几乎没有一家像苹果这样规模的企业表露出对创始人如此强烈的依附感,或是在最巅峰的时期失去了自己的创始人。在苹果1985年解雇乔布斯后的几年时间里,苹果业绩开始逐步下滑。直到乔布斯1997年重返苹果之后,才止住了苹果业绩的进一步下滑。

乔布斯同时还留下了关于他善变的管理方式的无数的故事,如他不喜欢时,会称员工或员工的想法为“愚蠢”。像微软、谷歌、亚马逊这样的竞争对手,乔布斯又显露出其好战的一面。2010年4月,当Adobe采用一系列手段哭诉苹果的iPhone和iPad不支持其Flash视频格式后,乔布斯洋洋洒洒写下一篇1600字的随笔,解释Flash已经过时,不适用于移动设备。

乔布斯对苹果的硬件和软件维持了高标准。他要求,从消费者走进苹果零售店的那一瞬间起,苹果应当为消费者提供“酷毙”的美感,以及易于使用的体验。他对产品开发和设计中的小细节非常关注,这给苹果产品带来了一些最具特色的功能。而乔布斯在舞台上的演讲方式则能够激起外界的无穷兴趣,这也是其他同行无法比拟的。

在多次苹果的产品发布活动上,乔布斯形成了一个著名的口头禅,即“还有一件事(There is one more thing)”。在乔布斯说这句话之后,苹果往往会发布最重要的新闻。他要求苹果员工对产品严格保密,这一策略确保了外界对苹果新产品的兴趣。

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/