Программирование для iPhone

iPhone SDK Programming Maher Ali WILEY w iley.com ПРОГРАММИРОВАНИЕ для iPhone Разработка мобильных приложений с пом...
Author:  Махер Али

8 downloads 1009 Views 25MB Size Report

This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!

Report copyright / DMCA form





П олучая обновления информации о местоположении, мы сохраняем эти локации в массиве. Получив NO_OF_LOCATlONS, мы делаем доступ­ ной левую кнопку панели, изменяем ее заголовок иа Next (Далее) и указы­ ваем первую локацию на карте. М етод c e n te r M a p : используется для отображения локации на карте. В качестве входных параметров методу передается порядковый номер лока­ ции в массиве отслеженных местоположений. Он извлекает информацию о широте и долготе, устанавливает центр карты в этой точке и центриру­ ет карту. В дополнение он открывает информационное окно, отображаю­ щее время, когда местоположение было отслежено. Все это делается с по­ мощью JavaScript, как показано ниже. Наконец, мы выполняем код

333

Jav aS crip t посредством метода веб-представления s t г in g B y E v a lu a t in g J a v a S c r i p t F r o m S t r i n g :. var map = new GMap2(document.getElementById(" map_canvas")); map.secMapType(G_HYBRID_MAP); map. setiCenter (new GLatLng (37 .331689 , -122.030731), 18); m ap.panTo(map.getCenter{)); map.openInfoWindow(map.getCenter(), d o c u m e n t .crea с e T e x t N o d e ("L o c : (1/1), Time: 2008-08-06 19:51:27 -0500"));

Н и ж е изображ ен сним ок экран а отслеж иваю щ его прил о ж ен и я во вре­ мя записи передвиж ений (рис. 12.7), а такж е во врем я п росм отра одной из записанны х л окаци й (рис. 12.8). -iiiCarrier ^

pTeviEHii

7:59 A M

L o c a t io n s : 2 0

GS

stop

Р и с . 1 2 .7 . С нимок экрана отслеж и ваю щ его п ри л ож ен и я во врем я за п и си п ередв иж ен и й

..■aCarrier ^

Previous

8:00AM

В

Locations; 20

Loc: (1/1), Time: 2010-01-22 07:59:29 -080^

Р и с . 1 2 .8 . С н и м ок экрана отслеж и ваю щ его п р и л ож ен и я во врем я п росм отр а локации

334

Приложение сталкивается с некоторыми этическими проблемами, а может, и вопросами легальности. Если вы захотите запустить данное приложение и спрятать устройство в чьей-нибудь сумке или автомобиле, лишний раз подумайте* Незаконная слежка не только неэтична, но и мо­ жет привести к серьезным последствиям вплоть до тюрьмы. Можно моди­ фицировать приложение и добавить формирующиеся в реальном времени отчеты о передвижениях, доставляемые заинтересованным лицам. Оста­ вим это вам в качестве упражнения. Листинг 12.11. Реализация класса контроллера представления LocationsViewController, используемого в отслеживающем приложении i i m p o r t "Locat ionsViewCont rol ler. h “ tidefine NO_OF_LOCATIONS 100 #define MIN_DISTANCE 100 Qimpleinentat ion Loca t ions Vi ewCon t го 1 ler — (void) locationManager: (CLLocationManager *)m anager d idU p d a t e T o L o c a t i o n : (CLLocation *) newLocat ion f r omLocation: (CLLocation *) oldLocation( noUpdates++; [locations addObject :newLocation] ; sel f . t i t l e = [NSString stringWithFormat:®"Locations: % i “ , noUpdates]; i f ( n o U p d a t e s == 1) { [self c e n t e rMa p : 0 1 ;

) if

}

(noUjpdates >= NOjOF_LOCATIONS) { [locationMgr stopUpdatingLoeation] ? l eftButton.enabled = YES; rightButton.title = @"Next“ ; current = 0; [self cent e rMa p :current];

)

— (void) cent erMap: (NSUInteger) index{ CLLoca t i o n *loc - [locations objectAtlndex:index]; N S S t r i n g *js = [NSString stringWithFormat: @"var map = " "n e w GMap2 (d oc u m e n t .get El ement By Id (\ "map_canvas \ ■)); “ “m a p .setMapType (G_HYBRID_MAP); ■ “map.setCenter(new GLatLngltlf, % l f ) , 18);" “m a p .panTO (map.getCenter ());" ’’m a p .openlnf owindow (map.getCenter (J, ■ "document ^createTextNode (\ “L o c : (% i / % i ), T i m e : %G\ *)),;“ , [loc coordinate]'.latitude, [loc c o o r d i n a t e ] .longitude, index+1, (locations count], [loc t i m estamp]]; [webview stringByEvaluatingJavaScriptFroiitStrlng: j s ] ;

} — (id) i n i t W i t h N i b N a m e : (NSString *) nibNameOrNil b undle: (NSBundle *)nibBundleOrNil ( if (eelf= [super initWithNifcNaime: nibNameOrNil Ь ш к Ц е : nibBundleOrNil]) { rightButton * [ [UIBarButtonltem alloc] initWithTitle:0*Stop" s t y l e :U I B a r B u t t o n l t e m S t y l e D o n e target:self a c t i o n :© s e l e c tor(stopOrNext)]; s e l f .navigat i o n l t e m .rightBarBut tonl t em = r i g h t B u t t o n ? leftButton - [[UIBarButtonltem alloc] i n i t w ithTitl e :@ "Pre v i o u s ■ sty l e :UIBarButtonltemStyleDone target reelf act i o n :^selector (preV) ] ; s e l f .navigationl tem. le ftBarBut t on 11 e m = lef t B u t t o n ; l eftButton.enabled - NO;

} return- s e l f ;

335

} -(void) s t o p O r N e x t { i f ([ r i g h t B u t t o n . t i t l e i s E q u a l T o S t r i n g : @ " S t o p " ] == Y E S > { [locationMgr stopUpdatingLocationJ ? l e f t B u t t o n . e n a b l e d = YES; rig h t B u t t o n . t i t l e = ©"Next"; cu r r e n t = 0; [self c e n t e r M a p :c u r r e n t ];

) else i f (current < ([loc a t i o n s c o u n t ] - l ) ) { [self c e n t e r M a p : + + c u r r e n t ] ;

}

}

-(void)prev{ i f (current > 0 & &

(current < c u r r e n t = c u r r e n t -1; [self c e n t e r M a p :c u r r e n t ];

)

[locations

c o u n t ) ) ){

}

-(void) l o a d V i e w { locations = [[NSMutableArray arrayWithCapacity:10] retain]; l o c a t i o n M g r = [ [ C L L o c a t i o n M a n a g e r a l l o c ] init]; locationMgr.distanceFilter = M I N _ D I S T A N C E ; l o c a t i o n M g r . d e l e g a t e - self; n o U p d a t e s = 0; CG R e c t r e e t F r a m e = [Ul S c r e e n m a i n S c r e e n ] .a p p l i c a t i o n F r a m e ; w e b V i e w = [ [ U l W e b V i e w alloc] i n i t W i t h F r a m e :r e e t F r a m e ] ; NSString *htmlFilePath = [ [ NSBundle m a i n B u n d l e ] pathForResource:@"map3" ofType:@"html"] ; NSData * d a t a = [NSData d a t a W i t h C o n t e n t s O f F i l e : h t m l F i l e P a t h ] ; [webView l o a d D a t a s d a t a M I M E T y p e : @ " t e x t / h t m l " t e x t E n c o d i n g N a m e :@ "ut f -8" b a s e U R L : [ N S U R L U R L W i t h S t r i n g : ® " h t t p : / / m a p s . g o o g l e . c o m / "]]; [locationMgr startUp d a t i n g L o c a t i o n ] ; self. v i e w = webView;

} -(void) d e a l l o c

{ [rightButton r e l e a s e ] ; [leftButton r e l e a s e ] ; [ l o c a t i o n M g r r e l ease]; [locations release]; [super d e a l l o c ] ;

} @end

12.5. Работа с почтовыми индексами П очтовая служ ба С оединенны х Ш татов (U n ite d S ta te s P o stal Service (U S P S )) исп ользует кодирую щ ую систему д л я эф ф ек ти вн о й доставки по­ чты в пределах СШ А . П одразумевается, что к аж ды й п отен ц и альн ы й по­ лучатель почты ж ивет в определенной зоне, представл ен н о й почтовым индексом (рис. 12.9). Т еоретически почтовы е и н дексы п р и вязан ы к гео­ граф ическом у местоположению . Сущ ествую т различны е доступны е базы дан н ы х п очтовы х индексов. О н и отличаю тся точностью и ценой. М ож но представи ть базы данны х, со­ относящ ие ш ироту и долготу к данном у почтовом у индексу, к ак описы­ ваю щ ие центр области, обслуж иваю щ ей дан ны й почтовы й индекс. Суще-

336

ствует несколько мест, где вы можете приобрести базу данных почтовых индексов Соединенных Штатов. Вы даже можете бесплатно загрузить акутальную базу с сайта [1]. Содержимое файла почтовых индексов США [1] разделено запятыми. На­ пример, последние несколько записей в файле выглядят следующим образом: 89508, Reno, NV, 39. 5296329,-119.8138027,Washoe 91008 ,Duarte, СА, 34 .1394513 ,-117 .9772873,Los Angeles 92058, Oceanside, CA, 33.1958696,-117.3794834, San Diego 94 50 5, Discovery Bay, CA, 37.9085357, -121.6002291 rContra Costa 95811, Sacr ament о tCA,38.5815719,-121.4943996, Sacramento

Ч тобы ответить на запросы типа «получить почтовые индексы в радиу­ се 10 м иль от 68508», необходимо выполнить следующие действия.

Р и с . 1 2 .9 . Зоны почтовых индексов Соединенных Штатов [2 |

1. С оздайте SQ L ite-таблицу z ip c o d e s . Для эффективного поиска ре­ комендуется поместить данные в базу. Для хранения почтовых индексов мож но использовать следующую таблицу: TABLE zipcodes < zipcode int N O T NULL PRIMARY KEY, latitude longitude float(10,8), state v a r c h a r ( 2 ) , city varchar{128) , county v a r c h ar<128))

CREATE

f l o a t (10,8),

Зд есь z i p c o d e будет первичным ключом, и для каждого почтового индекса у нас будут поля — l a t i t u d e , l o n g i t u d e , s t a t e , c i t y и c o u n ty . 337

2. Зап о лн и те таблицу z i p c o d e s географ ическим и дан н ы м и почтовы х индексов, полученны х из текстового ф айла. Д ан н ы е х р ан я тся в A S C IIф ай ле и разделены точкой. И сп ользуй те объект N S S c a n n e r д л я и звлече­ ния значений. П олученны е зн ач ен и я д л я каж дой строки будут и спользо­ ваться в качестве входны х парам етров д л я S Q L -вы р аж ен и я i n s e r t . 3. Создайте класс O bject-C дл я ответов на запросы . С оздав базу данных, нуж но разработать новы й класс, которы й будет отвечать на географ иче­ ские запросы . Главный запрос, на которы й бы мы хотели ответить, — «по­ лучить все почтовы е индексы , находящ и еся в п ределах 10 м и ль о т 20007». Этот запрос м ож но реализовать с пом ощ ью следую щ его метода: -(NSArray*)zipcodesNearLatitude:(float)lat withinDistance:(float)distance;

andLongitude:(float)

Ion

Р ассм отрим возм ож ную реализаци ю этого метода. Его основное на­ значение — вы полнение и обработка результатов следую щ его S Q L вы раж ения: SELECT Z.zipcode F R O M zipcodes A S Z W H E R E D i s t a n c e (l a t i t u d e l , latit u d e 2 , Z . l a t i t u d e ,

Z.longitude)

<= d i s t a n c e

Вы раж ение SELECT находит все п очтовы е индексы , д л я которы х рас­ стояние м еж ду почтовы м индексом ( l a t i t u d e , l o n g i t u d e ) и данной точкой ( l a t i t u d e ! , I a t i t u d e 2 ) расп олагается в пределах зн ачен ия d i s t a n c e (в килом етрах). Вы научились писать код д л я этих S Q L -вы раж ен и й , создавать С -ф ун кц и и и исп ользовать и х в S Q L -запросах. Р еал и зу й т е ф ункцию D i s t a n c e () в приведенном вы ш е S Q L -вы раж ен и и самостоятельно. Л и сти н г 12.12 п редставляет С -реализацию . Листинг 12.12. С-реализация пользовательской функции Distance v o i d dist a n c e ( s q l i t e 3 _ c o n t e x t *context, int nargs, char *errorMessage; double pi = 3.14159265358979323846; I f ( n a r g s 1= 4)(

sqlite3_value

**values)(

e r r o r M e s s a g e * - W r o n g # o f a rgs. D i s t a n c e ( l a t l , l o n l ,l a t 2 ,l o n 2 ) "; s qlite3_result_error(context, errorMessage, s t r l e n ( e r rorMessage)); return;

} if ((sql i t e 3 _ v a l u e _ t y p e (v a l u e s [0 J ) != S Q L I T E _ F L O A T ) I I ( s q l i t e 3 _ v a l u e _ t y p e ( v a l u e s (1]) != S Q L I T E _ F L O A T ) II (sql i t e 3 _ v a l u e _ t y p e ( v a l u e s [21) != S Q L I T E _ F L O A T ) II (s q l i t e 3 _ v a l u e _ t y p e ( v a l u e s [3]) != S Q L I T E _ F L O A T ) ){ e r r o r M e s s a g e = "A11 f o u r a r g u m e n t s m u s t b e o f t y p e float."; sqlite3_resul t _ e r r o r ( c o n t e x t , errorMessage, s t r l e n ( e r r o r M e s s a g e ) ) ; return;

) d o u b l e latitudel, long i t u d e l , I a t i t u d e 2 , l o n g i t u d e 2 ; l a t i t u d e l = s q l i t e 3 _ v a l u e _ d o u b l e ( v a l u e s [ G J ); l o n g i t u d e l = s q l i t e 3 _ v a l u e _ d o u b l e ( v a l u e s [1]); l a t i t u d e 2 = s q l i t e 3 _ v a l u e _ d o u b l e ( v a l u e s [2}); l o n g i t u d e 2 = s q l i t e 3 _ v a l u e _ d o u b l e ( v a l u e s [3]);

338

double x = sin(latitudel * pi/180} * sin (latitude2 * pi/180) + c o s (latitudel • pi/180} * c o s (latitude2 * pi/180) * cos (abs ((longitude2 * p i /180) - (longitudel * pi/180))); x = a t a n ((sgrt (1 - pow(x, 2))) / x ) ; x = {1.852 * 60.0 * {(x/pi)*180)) / 1.609344; sqlite3_result_double(context, x) ;

»

12.6. Резюме Эта глава была посвящена теме информации о местоположении. В разд. 12.1 мы говорили о фреймворке Core Location и его использовании в приложениях, предоставляющих информацию о местоположении. В разд. 12.2 мы рассмотрели простую программу, предоставляющую ин­ формацию о местоположении. В разд. 12.3 вы получили представление о геокодировании и научились транслировать почтовые адреса в геогра­ фические координаты. Из разд. 12.4 вы узнали, как отслеживать передви­ ж ения устройства и отображать эту информацию на картах местности. В разд. 12.5 были представлены соотношения почтовых индексов и геогра­ фической информации. В этом разделе вы ознакомились с формулой, по которой вычисляется расстояние между двумя локациями.

Глава 13 Работа с устройствами

В этой главе мы рассмотрим использование некоторы х устройств, д о ­ ступны х в iPhone. И з разд. 13.1 вы узнаете, как использовать ак сел ер о ­ метр. В разд. 13.2 будет рассказано, как проигры вать небольш ие звуковы е ф айлы , а в разд. 13.3 — как воспроизводить видеоф ай лы . И з разд. 13.4 вы узнаете, как получать инф орм ацию об устройстве iP h o n e /iP o d T ouch. И с­ пользование камеры и ф отобиблиотеки будет описано в разд. 13.5. И тоги главы вы найдете в разд. 13.6.

13.1. Работа с акселерометром iP h o n e оборудован простым в исп ользовании акселером етром . Ак­ селерометр позволяет определить текущ ее полож ен и е устройства в ЗО -пространстве. Вы запраш иваете обновления и н ф орм ац и и о п олож е­ нии устройства с данной частотой (о т 10 до 100 обновлений в секунду) и при каж дом обновлении получаете три зн ачения с плаваю щ ей точкой. Эти значения представляю т ускорение в пространстве по осям х , у и z. У скоре­ ние по каж дой оси вы числяется по ф орм уле g х s, где g — у скорени е сво­ бодного падения (1 g = 9,8 м /с 2). П олож ите iP hone перед собой и представьте ось, проходящ ую через кнопку Ноте (В озврат) и уш ной ди н ам и к перп ен ди кул ярн о полу. Э та ось будет осыо у . П олож ительны е зн ачен и я у показы ваю т, что iP h o n e у ск о р я­ ется по данной оси вверх, а отрицательны е — вн из по направлен и ю к полу. О сь х проходит справа налево п ерпендикулярно оси у . П олож и тельн ы е значения показываю т, что устройство передвигается вправо, о три ц атель­ ные — влево. О сь z проходит через устройство. О три ц ател ьн ы е значения показываю т, что устройство двигается от вас, а п олож и тельн ы е — что оно двигается к вам. И з-за си лы п р и тя ж ен и я у стр о й ств о буд ет п ер е д а в а ть о тл и ч н ы е от нуля зн а ч е н и я по н екоторы м или всем осям , д а ж е н ах о д ясь в неп о­ д ви ж н ом со стоян и и . Н ап р и м ер , есл и вы д е р ж и т е у ст р о й ств о перед со­ бой в п о р тр етн ой о р и ен тац и и (р и с. 13.1), оси х и z б уд у т п о к азы в ать 0 g, а зн ач ен и е по оси у буд ет —1 g. П рощ е говоря, к у ст р о й ств у не п р и ­ лож ен о н и к ак и х сил, п ередвигаю щ их его в л е в о /в п р а в о и л и в п е р е д /н а ­ зад, но су щ ествует си л а B i g , п ередви гаю щ ая у ст р о й ств о вн и з, — сила п р и тяж ен и я.

340

Р и с. 13.1. Неподвижный iPhone, передающим значения вектора акселерометра (0, —1,0)

Если вы держите устройство в альбомной ориентации (рис. 13.2), то на ось .г влияет сила гравитации. Значение компонента .г вектора, пере­ даваемого акселерометром, будет 1 g.

Р и с. 13.2. Неподвижный iPhone, передающий значения вектора акселерометра ( 1 , 0 . 0 )

Если вы держите устройство, как показано на рис. 13.3. значение будет —1 g. Если вы положите iPhone на стол лицевой стороной вверх, значение г будет —1 g. а если лицевой стороной вниз - 1 g.

341

Р и с . 1 3 .3 . Н еп одв и ж н ы й iP h o n e, п ередаю щ и й зн ач ен и я вектора а к сел ер ом етр а ( —1 , 0 , 0 )

Е сли вы держ ите iP h o n e ли цевой стороной к себе (см . рис. 13.1) и на­ клоните его вправо, зн ачения х и у начнут увел и чи ваться. Е сли вы н акло­ ните его влево, значение у начнет возрастать, а х — ум еньш аться. П рим ер. Рассмотрим простое прилож ение, дем онстрирую щ ее использо­ вание акселерометра. П ример покажет, как настроить акселером етр и пере­ хватить встряску у прижатие и толчок. В дополнение програм м а будет со­ общать, когда iP hone находится в портретной ориентации с кнопкой Ноте (В озврат) вверху или внизу перпендикулярно полу. Д л я исп ользован ия акселером етра вы п олн и те следую щ ие дей стви я. 1. Получите разделяемый объект акселерометра. В распоряж ении прило­ жения есть один акселерометр. Используйте метод s h a r e d A c c e le r o m e t e r для получения этого объекта. М етод объявлен следую щ им образом: +

(UIAccelerometer

*)

sharedAccelerometer

2. Н астройте акселером етр. Н астройте частоту обновлен и й , используя свойство u p d a t e l n t e r v a l , объявленн ое следую щ им образом : ©property(nonatomic)

N S Ti melnterval

updatelnterval;

Здесь N S T im e ln t e r v a l объявлено как d o u b le . Значение, передаваемое этому свойству, изменяется от 0 , 1 (частота 10 H z) до 0 , 0 1 (частота 100 Hz). Н еобходим о такж е настрои ть свойство делегата d e l e g a t e , о бъ явлен ­ ное как ©property(nonatomic,

a s s ign )

id delegate

Протокол U I A c c e le r o m e t e r D e le g a t e имеет один необязательный ме­ тод a c c e l e r o m e t e r : d i d A c c e l e r a t e : , объявленный следующим образом: — (void) a c c e l e r o m e t e r : ( U I A c c e l e r o m e t e r * ) a c c e l e r o m e t e r didAccelerate:

342

(UIAcceleration

*)acceleration;

Методу передается объект акселерометра и экземпляр U I A c c e le r a t io n . Объект U IA c c e le r a tio n содержит значения ЗБ-вектора (х , у и г) и время ( t imestamp). Л истинг 13.1 показывает объявление класса делегата приложения с ис­ пользованием акселерометра. Делегат приложения заимствует протоколы U IA ppl i c a t io n D e le g a te и U IA c c ele ro m eter D ele g a te . В дополне­ ние он оперирует предыдущим значением акселерометра в переменной экземпляра a c c e le r a tio n V a lu e s . Листинг 13.1. Объявление класса делегата приложения для примера использова­ ния акселерометра # import @ interface AccelAppDelegate : NSObject cUIApplicationDelegate, UlAccelerometerDelegate> { UlWindow *window; UIAccelerationValue accelerationValues [3];

@end

Листинг 13.2 демонстрирует реализацию класса делегата приложеиия. Метод a p p lic a tio n D id F in is h L a u n c h in g : начинается с настройки акселерометра на частоту обновлений 10 Hz и установки поля d e l e g a t e на экземпляр делегата приложения. В методе a c c e le r o m e t e r : d id A c c e le r a t e : находится логика распознавания, описанная выше. Для распознавания встряски доста­ точно проследить изменения ускорений хотя бы по двум осям. Мы ис­ пользуем значение изменения, равное Зд, для каждой оси. Например, выражение: BOOL x_big_difference = (fabs(x - accelerationValues[0]) >3);

вернет значение YES (1), если разница между предыдущим и текущим значениями ускорений по оси х больше Зд. Чтобы распознать портретную ориентацию iPhone с осью Ноте (Воз­ врат) в динамик, перпендикулярной полу, когда кнопка Ноте (Возврат) находится внизу, мы должны убедиться, что значения х и г равны 0 с не­ которой погрешностью, а значение у составляет приблизительно - 1 . Ана­ логично при распознавании перевернутой ориентации iPhone значение у должно быть около 1 д. Д ля распознавания прижатия/толчка iPhone метод распознает значительное ускорение по оси г с небольшими изменениями по х и у. Если значение z изменилось в сторону отрицательного ускорения, мы рассм атриваем это как толчок. Если же значение изменилось в поло­ ж ительную сторону, мы интерпретируем это как прижатие.

343

Листинг 13.2. Реализация класса делегата приложения для примера использова­ ния акселерометра #lmport " A c c e l A p p D e l e g a t e . h " #define B E T W E E N ( a r g , vl, v2) {(arg >= vl) & & (arg < = v 2 ^implementation A c c e l A p p D e l e g a t e — (void) a c c e l e r o m e t e r : ( U I A c c e l e r o m e t e r * ) a c c e l e r o m e t e r

))

didAccelerate:(UIAcceleration *)a c c e l e r a t i o n { U I A c c e l e r a t i o n V a l u e x, y, z; x = accelerations? у = acceleration.y; z = a c c e l e r a t i o n .z ; N S L o g ( @ BX: % 4 . 2 f , Y : % 4 . 2 f , Z : % 4 . 2 f ", X, у, z) ; // в с т р я с к а B O O L x_big__difference = ( f a b s ( x - a c c e l e r a t i o n V a l u e s [0]) >3); B O O L y _ b i g _ d i f f e r e n c e = ( f a b s ( y — a c c e l e r a t i o n V a l u e s [1]) >3); B O O L z _ b i g _ d i f f e r e n c e = (f a b s ( z - a c c e l e r a t i o n V a l u e s 12]) >3); int a x e s = x _ b i g _ d i £ f e r e n c e + y _ b i g _ d i f f e r e n c e + z _ b i g _ d i f f e r e n c e ;

i f (axes>= 2){ N S L o g (@ "i P h o n e S h a k e n

19 );

} //ориентация i f {B E T W E E N (X , -0.0 5 , 0.05) && B E T W E E N ( y , -1, - 0 . 9 5 ) & & BETWEEN(z, -0.05, 0 . 0 5 Ж N S L o g ( @ " i P h o n e p e r p e n d i c u l a r to g r o u n d # H o m e b u t t o n d o w n " ) ?

> if (BETWEEN (X, -0. 05', 0.05)

&& B E T W E E N (y, 0.95, BETWEEN{z, -0.05, 0.05)){ N S L o g ( @ “i P h o n e p e r p e n d i c u l a r t o g r o u n d ,

1)

&&

H o m e b u t t o n up " ) ;

} // п р и ж а т и е / т о л ч о к B O O L x _ c h a n g e = ( f a b s ( x - a c c e l e r a t i o n V a l u e s [ 0 J ) < 1); B O O L y ^ c h a n g e = (f a b s ( y - a c c e l e r a t i o n V a l u e s [1]) < 1); B O O L z ^ c h a n g e = (fabs(z — a c c e l e r a t i o n V a l u e s [2J ) > = 3)? if (x _ c h a n g e & & y _ c h a n g e && z _ c h a n g e ) { if (z > a c c e l e r a t i o n V a l u e s [2)) NSLog(G"hug");

else N S L o g (@ Ho u n c h ");

) a c c e l e r a t i o n V a l u e s [0] a c c e l e r a t i o n V a l u e s (1] a c c e l e r a t i o n V a l u e s [2]

= x; = y; = z;

} - (void) a p p l i c a t i o n D i d F i n i s h L a u n c h i n g ; ( U I A p p l i c a t i o n * ) a p p l i c a t i o n CGRect fullscreen = [[UlScreen mainScreen] bounds]; w i n d o w - [ [ U l W i n d o w all o c ] i n i t W i t h F r a m e :f u l l s c r e e n ] ; UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; a c c e l e r o m e t e r . u p d a t e l n t e r v a l = 0.1; // 10Hz a c c e l e r o m e t e r . d e l e g a t e = self; [w i n d o w m a k e K e y A n d V i s i b l e ] ;

) - void) d e a l l o c { [window r e l e a s e ] ; [super d e a l l o c ] ;

) @end

344

{

13.2. Аудио В этом разделе мы рассмотрим проигрывание коротких звуковых фай­ лов ( продолжительностью менее 30 секунд). Чтобы воспроизвести корот­ кий звуковой файл, необходимо зарегистрировать файл как системный звук и получить его дескриптор. После этого, используя дескриптор, вы можете проиграть этот звук. Если вы закончили работу и не хотите вопроизводить его снова, нужно высвободить этот системный звук. Чтобы зарегистрировать звуковой файл в качестве системного звука, используйте функцию A u d ioS ervicesC reateS ystem S ou n d ID (), объ­ явленную следующим образом: OSStatus AudioServicesCreateSystemSoundID( CFURLRef inFileURL, SystemSoundlD *outSystemSoundID)

Первый параметр - это CFURLRef (или его аналог, экземпляр NSURL), а второй — ссылка SystemSoundlD. Эта переменная, 32-битное беззна­ ковое целое, будет хранить ID системного звука. Возвращаемое значение должно быть 0, что означает успешную регистрацию системного звука. Чтобы воспроизвести системный звук, используйте функцию A u d io S e r v ic e sP la y S y s te m S o u n d ( ) , объявленную как void AudioServicesPlaySystemSound(SystemSoundlD ip.SystemSoundlD)

Вы передаете дескриптор системного звука, полученный от предыду­ щей функции. Чтобы включить вибрацию, можете использовать предо­ пределенный системный идентификатор k System SoundID _V ibrate. Д ля высвобождения системного звука используйте функцию A u d io S e r v ic e s D is p o s e S y s te m S o u n d lD O , объявленную следую­ щим образом: OSStatus AudioServicesDisposeSystemSoundID(SystemSoundlD inSystemSoundID)

В качестве параметра передается дескриптор системного звука, полу­ ченный от функции регистрации. П ример. Создадим приложение, проигрывающее звуковой файл каж­ дую минуту. Листинг 13.3 показывает объявление класса делегата прило­ жеиия. Обратите внимание на директиву #in c lu d e для файла заголовка . Вам также нужно добавить библио­ теку A u d io T o o lb o x . framework к проекту в XCode. Листинг 13.3. Объявление класса делегата приложения, демонстрирующего проигрывание небольших звуковых файлов Кimport include

345

©interface A u d i o A p p D e l e g a t e

: NSObject



{

UlWindow *window; SystemSoundlD audi o S I D ;

} @end

Л и сти н г 13.4 дем онстрирует реали зац и ю класса делегата п р и ло­ жения. Звуковой ф ай л хран и тся в упаковке при лож ен и я. В методе a p p l i c a t i o n D i d F i n i s h L a u n c h i n g : м ы сн ачала получаем абсолю тны й путь к ф ай лу s o u n d , c a f . Затем д л я этого пути создается объект NSURL, используя м етод f i l e U R L W i t h P a t h : i s D i r e c t o r y П осле этого р е­ гистрируется систем ны й звук. Т и п ы CFURL и NSURL взаимозаменяемы» поэтом у мы передаем объект NSURL вм есто ссы лки н а CFURL, CFURLRef. Если не возн икло ош ибок, зв у к воспроизводится. М етод p l a y : проигры вает звук, после чего н астраивает тай м ер на соб­ ственны й вы зов раз в минуту. Листинг 13.4. Объявление класса делегата приложения, демонстрирующего проигрывание небольших звуковых файлов timport " A u d i o A p p D e l e g a t e . h " @ implementation A u d i o A p p D e l e g a t e

-(void) a p p l i c a t i o n D i d F i n i s h L a u n c h i n g : ( U I A p p l i c a t i o n * ) a p p l i c a t i o n { CG R e c t

screenFrame *

window =

[[ U l S c r e e n

[ [ U l W i n d o w alloc]

NSString *filePath =

mainScreen]

[ [NS B u n d l e m a i n B u n d l e ]

pathForResource:®"sound" NSURL

*aFileURL =

OSStatus

bounds];

i n i t W i t h F r a m e :s c r e e n F r a m e ] ;

o f T y p e : @ Hc a f "];

[NSURL f i l e U R L W i t h P a t h : f i l e P a t h i s D i r e c t o r y :N O ] ;

error =

AudioServicesCreateSystemSoundlD( (CFURLRef)aFileURL,

&audioSID);

i f (error == 0) [self p l a y i n i l ] ; [ window m a k e K e y A n d V i s i b l e ] ;

) -(void) play: (NSTimer*) theTim e r { AudioServicesPlaySystemSound(audioSID) ; // н а с т р а и в а е м е ж е м и н у т н о е в о с п р о и з в е д е н и е [ NSTimer s c h e d u l e d T i m e r W i t h T i m e l n t e r v a l :60.0 t a r g e t :s e l f s e l e c t o r :© s e l e c t o r ( p l a y :) u s e r l n f о :n i l

repeats:N0];

1 -(void) d e a l l o c

{

AudioServicesDisposeSystemSoundXD (audioSID); [ w i ndow r e l e a s e ] ;

[super d e a l l o c ] ;

} @end

346

13.3. Видео Чтобы воспроизвести видео в вашем приложении, используйте класс

MPMoviePlayerController. Создайте и инициализируйте его экзем­ пляр, после чего запросите воспроизвести видео. Этот контроллер про­ игрывает видео в полноэкранном режиме. Когда воспроизведение закон­ чено, экран приложения снова становится видимым. Следующий код воспроизводит файл MyMovie.m4v, хранящийся в упаковке приложения. NSString *filePath = [ [NSBundle main.Bundle] pathForResource:@"MyMovie* of Type:8"m4v"]; NSURL *fileUrl = [NSURL fileURLWithPath:filePath]; MPMoviePlayerController *movieController = [[MPMoviePlayerController alloc] initWithContentURL:fileUrl]; movieController. backgroundColor = [UlColor grayColor]; movieController .movieControlMode = MPMovieControlModeVolumeOnly; [movieController play];

Данный код сначала находит полный путь к видеофайлу в упаковке и использует его для создания экземпляра NSURL. Затем создается экзем­ пляр MPMoviePlayerController, инициализирующийся посредством метода initWithContentURL:, которому передается экземпляр NSURL. Опционально мы можем установить цвет фона и режим управления. Д ля свойства movieControlMode можно определить (или принять значение по умолчанию) MPMovieControlModeDefault для появ­ ления стандартных элементов управления (кнопок начала и остановки воспроизведения, временной шкалы и т. д.). Чтобы скрыть все элемен­ ты управления, используйте MPMovieControlModeHidden. Метод MPMovieControlVolumeOnly используется для отображения только ре­ гулятора громкости. После фазы инициализации контроллер воспроизводит видео с по­ мощью метода p la y .

13.4. Информация об устройстве Класс UlDevice используется для предоставления информации о вашем iPhone/iPod Touch. Существует единственный экземпляр класса, который можно получить с помощью метода класса currentDevice. Рас­ смотрим фрагменты информации, которые вы можете получить посред­ ством данного экземпляра. • Уникальный идентификатор. Вы можете получить строку, уникаль­ но идентифицирующую ваш iPhone, с помощью u n i q u e l d e n t i f i e r , объявленного следующим образом: ©property(nonatomic,

readonly, retain) NSString *uniqueIdentifier

347

• О перационная система. П олучить им я оп ерацион ной систем ы м ож ­ но посредством свойства sy stem N a m e , объявл ен н ого как ©property(nonatomic,

readonly,

ret a i n )

NSString

*uniqueldenti£ier

• Версия операционной системы. Вы м ож ете п олучить версию о п ера­ ционной систем ы с пом ощ ью свойства s y s t e m V e r s i o n . О н о о б ъ яв­ лено следую щ им образом: 8property(nonatomic.

readonly,

retain)

NSString

*systemVersion

• М одель. О п ред елить разли ч и е м еж ду iP h o n e и iP o d T o u ch м ож но по­ средством свойства m o d e l, объявленного как ©property(nonatomic,

readonly,

r etain)

NSString

*model

• О риентация. О риентацию устройства м ож но у стан ови ть с помощ ью свойства o r i e n t a t i o n . С войство объявлен о следую щ им образом: S p r o p e r t y ( n o n a t o m i c , readonly)

UIDeviceOrientation

orientation

Возмож ные значения: • U ID e v i с e O r i e n t a t i onU nknow n; ^ U I D e v ic e O r ie n ta tio n P o r tr a it; * U I D e v ic e O r ie n ta tio n P o r tr a itU p s id e D o w n ; AU ID e v i с eO r i e n t a t i o n L a n d sс a p e L e f t ; * U I D e v ic e O r ie n t a t i o n L a n d s c a p e R ig h t ; ^ U I D e v ic e O r ie n t a t io n F a c e U p ; a UIDe v i c e O

r i e n t a t io n F a c e D o w n .

13.5. Производство и просмотр снимков В этом разделе вы научитесь и сп ользовать кам еру д л я производства снимков. Вы узнаете, что прям ой доступ к кам ере ил и би б ли отеке ф ото­ граф ий отсутствует, поэтом у требуется использовать предоставленны й контроллер, которы й обрабаты вает взаим одействи е с пользователем при производстве и редактировании сним ков. К онтроллер предоставляет ко­ нечный вари ант изображ ения. Т от ж е контроллер м ож но и сп ользовать при просм отре сним ков, хранящ ихся в пользовательской библиотеке. С трук­ тура раздела следую щ ая. В подразд. 13.5.1 будут рассм отрен ы основные ш аги, необходим ы е д л я обеспечения доступа к кам ере и фотобиблиотеке, а в подразд. 13.5.2 — подробны й пример, дем онстрирую щ ий производство и просм отр сним ков.

348

13.5.1. Общий подход Чтобы получить доступ к камере или просмотреть снимки из пользова­ тельской библиотеки, необходимо использовать предоставляемый вам си­ стемой интерфейс. Главный класс, используемый для производства сним­ ков и просмотра уже существующих, - UllmagePickerController. Для производства или просмотра снимков выполните следующие действия. 1. П роверьте доступность действия. Хотите ли вы сделать новый сни­ мок или просмотреть уже существующий, необходимо проверить, доступ­ на ли данная функция. Метод класса UllmagePickerController, ис­ пользуемый для этих целей, - isSourceTypeAvailable:. 2. Создайте экземпляр контроллера. Если заданное действие доступ­ но, необходимо создать экземпляр UllmagePickerController, ини­ циализировать его и настроить на нужную функцию. Если тип источника недоступен, создавать контроллер не требуется. 3. Н астройте делегат. Метод UllmagePickerController будет обе­ спечивать взаимодействие с пользователем во время производства и про­ смотра снимков. Нужно настроить делегат на объект и реализовать спе­ циальные методы, чтобы получить результат. Делегат реализует протокол

UIImagePickerControllerDelegate. 4. О тобразите контроллер. Контроллер модально отображается поль­ зователю с помощью dspjdf метода presentModalViewController: animated: для существующего контроллера представления, передавая экземпляр UllmagePickerController в качестве первого параметра. 5. Обработайте выбор изображения. Когда пользователь выбира­ ет снимок, вызывается метод делегата imagePickerController :did FinishPickingMediaWithlnfo:. Вам нужно извлечь изображения из словаря и скрыть контроллер, который был модально отображен на экране. 6. Обработайте отмену. Если пользователь отменяет операцию, вызы­ вается метод делегата imagePickerControllerDidCancel:. Вам тре­ буется скрыть контроллер, который был модально отображен на экране.

13.5.2. Подробный пример Рассмотрим приложение, демонстрирующее использование класса

UllmagePickerController. Программа предоставляет пользователю два действия на выбор - сделать новый снимок или выбрать уже суще­ ствующий. В зависимости от выбора пользователя приложение настраи­ вает экземпляр класса UllmagePickerController и отображает его. Когда пользователь справится с задачей, результат (если он есть) станет фоном основного окна.

349

П рограм м а реали зует два класса — класс делегата п ри л о ж ен и я и про­ стой контроллер представления. Л и сти н г 13.5 п оказы вает объявлен и е класса делегата при лож ения C a m e r a A p p D e le g a te . Д ел егат п р и лож ен и я использует экзем п л яр класса M a i n C o n t r o l l e r д л я уп р ав л ен и я пользо­ вательским интерф ейсом. Листинг 13.5. Объявление делегата приложения для работы с камерой # import < U I K i t / U I K i t . h> # import "MainController.h" @ interface CameraAppDelegate : NSObject U l W i n d o w * wind o w ; MainController * viewController;



{

} ©property

(nonatomic,

retai n )

UlW i n d o w * window;

@end

Л и сти н г 13.6 дем онстрирует реализаци ю делегата п ри л о ж ен и я. М етод a p p l i c a t i o n D i d F i n i s h L a u n c h i n g : создает главное окн о и экзем п л яр контроллера представления M a i n C o n t r o lle r . Затем он д о б авл яет пред­ ставление данного кон троллера в качестве дочернего к главн ом у окну, по­ сле чего делает главное окно клю чевы м и видимым* Листинг 13.6. Реализация делегата приложения для работы с камерой #import ■CameraAppDelegate.h" @implementation C a m e r a A p p D e l e g a t e ©synthesize wi n d o w ; — (void) a p p l i c a t i o n D i d F i n i s h L a u n c h i n g : ( U I A p p l i c a t i o n *) a p p l i c a t i o n { win d o w = [[UlWindow alloc] i n i t W i t h F r a m e : [ [UlScreen mainScreen] viewController = [MainController alloc]; [w i n d o w addSubview:viewController.view]; [w i ndow makeKeyAndVisible];

bounds]];

) -(void) d e a l l o c [window

[euper

{ release]; dealloc];

) ©end

Л и сти н г 137 показы вает объ явлен и е к о н тро л л ер а пред­ ставления M a i n C o n t r o lle r . О н заи м ствует д в а п ротокола — U I I m a g e P i c k e r C o n t r o l l e r D e l e g a t e д л я обработки взаи м одей стви я с экземпляром U llm a g e P ic k e r C o n t r o lle r и U I A c t io n S h e e t D e le g a t e , обрабатываю щ ий взаимодействие со списком действий. Листинг 13.7. Объявление класса MainController приложения для работы с камерой ^import < U I K i t / U I K i t . h > в interface M a i n C o n t r o l l e r : UlViewController {

) Send

350

Л истинг 13.8 демонстрирует метод loadView класса Main Controller. Этот метод просто создает полноэкранное представление, на­ страивает его и связывает со свойством view контроллера представления. Листинг 13.8. Метод loadView класса MainController приложения для работы с камерой -(void)loadView { CGRect reetFrame = (UlScreen mainScreen].applicationFrame; U l V i e w * theView = [[UlView alloc] initWithFrame:reetFrame]; theView.backgroundColor - [UlColor darkGrayColor]; theView.autoresizingMask - UIViewAutoresizingFlexibleHeight UIViewAutoresizingFlexibleWidth; self. v i e w = theView; ItheView release]?

I

) Когда представление завершает загрузку, метод viewDidLoad вызы­ вается автоматически. В этом методе мы создаем список действий, предла­ гающий пользователю выбрать, делать новый снимок или выбрать уже су­ ществующий. Метод устанавливает контроллер представления в качестве делегата и показывает список действий в представлении (листинг 13.9). Листинг 13.9. Метод viewDidLoad контроллера представления -(void) v i e wDidLoad { UIActionSheet * actionSheet = [[UIActionSheet alloc] initwithTitle:§"Choose an option:" delegate:self cancelButton Tit l e :nil destructiveButtonTitle:nil otherButtonTitles :@’New Picture’ , ©■Select a Picture", nil]; [act ionSheet showlnview:self«view] ;

} Л истинг 13.10 показывает метод actionSheet iclickedButtonAt Index:, обрабатывающий нажатия кнопок списка действий. Если была нажата первая кнопка, мы проверяем, доступна ли камера. Д ля этого используется метод isSourceTypeAvailable: класса UllmagePickerController. Метод объявлен как +

(BOOL) isSourceTypeAvailable: (UI ImagePi ckerCon troll er Sour с eType)sour ceType

Единственный параметр типа UllmagePickerControllerSource Туре может принимать следующие значения:

• UIImagePickerControllerSourceTypePhotoLibrary — задает в качестве источника фотобиблиотеку; • UIImagePickerControllerSourceTypeSavedPhotosAlbum — в качестве источника определяет альбом камеры; • UIImagePickerControllerSourceTypeCamera — задает как ис­ точник встроенную камеру. 351

М етод возвращ ает YES, если заданны й источник доступен, и N0 в противном случае. Е сли кам ера доступна, м етод создает новы й экзем ­ п л яр класса U l l m a g e C o n t r o l l e r и устан авли вает свойство источн и ­ ка s o u r c e T y p e в значен ие U I I m a g e P ic k e r C o n t r o lle r S o u r c e T y p e Camera. С войство s o u r c e T y p e объявлено следую щ им образом: ©property

(nonatomic)

UIImagePickerControllerSourceType sourceType

Если наж ата вторая кнопка, мы повторяем предыдущ ие ш аги с тем исключением, что в качестве источника будем использовать U llm a g e P ic k e r C o n t r o lle r S o u r c e T y p e P h o t o L ib r a r y . После этого мы устанав­ ливаем делегат контроллера выбора и зображ ения в экзем пляр контроллера представления, устанавливаем свойство a llo w s I m a g e E d it i n g в YES и ото­ бражаем контроллер выбора изображ ения посредством вы зова метода кон­ троллера представления p r e s e n t M o d a l V i e w C o n t r o l l e r : a n im a t e d :. Свойство a llo w s I m a g e E d it i n g используется д л я определения, разреш е­ но ли пользователю редактировать изображ ение перед его возвратом. Листинг 13.10. Метод actionSheetxlickedButtonAtlndex:, обрабатывающий на­ жатия пользователем списка действий приложения для работы с камерой - ( v o i d ) a c t i o n S h e e t : ( U I A c t i o n S h e e t *) a c t i o n S h e e t clickedButtonAtIndex:(NSInteger)buttonlndex

{ [ac t i o n S h e e t re l e a s e ] ; UllmagePickerController *picker; if ( b u t t o n l n d e x == 0){ if ((J [ U l l m a g e P i c k e r C o n t r o l l e r i s S o u r c e Ty p e A v a i l a b l e : U I I m a g e P i c k e r C o n t r o l l e r S o u r c e T y p e C a m e r a ])

){ return;

} p i c k e r = [ [ U l l m a g e P i c k e r C o n t r o l l e r a l l o c ] init]; picker.sourceType UIImagePickerControllerSourceTypeCamera;

} else

{ if

((![UllmagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypePhotoLibrary])

H return;

> p i c k e r - [ [ U l l m a g e P i c k e r C o n t r o l l e r a l l o c ] i n it]; picker.sourceType = UllmagePickerCo ntrollerSourceTypePhotoLibrary;

} p i c k e r . d e l e g a t e - self; p i c k e r , a l l o w s I m a g e E d i t i n g = YES; [self p r e s e n t M o d a l V i e w C o n t r o l l e r :p i c k e r a n i m a t e d

: YES];

} К ак уж е бы ло сказано, контроллер вы бора изображ ен и й и н ф о р м и р у ­ ет, что пользователь выбрал изображение посредством вызова метода im a g e P i c k e r C o n t r o l l e r : d i d F i n i s h P i c k i n g l m a g e : e d i t i n g l n f о : сво­ его делегата. М етод объявлен следую щ им образом: - (void) imagePickerController: (UllmagePickerController

352

*)p i c k e r

didF in ishPi eking Image: (Ullmage *) image editinglnfo:(NSDictionary *)editinglnfo

Первый параметр, p ic k e r — это объект, контролирующий интерфейс выбора изображений. Второй параметр — изображение, выбранное поль­ зователем (возможно, после редактирования), а третий — это словарь, используемый для хранения информации о редактировании (если оно доступно). Для извлечения соответствующей информации из словаря применяются два кл юча: • U llm a g e P ic k e r C o n tr o lle r O r ig in a lIm a g e — для извлечения оригинального изображения (экземпляра U llm age) перед редакти­ рованием пользователя; • U IIm a g eP ick erC o n tro llerC ro p R ect — для получения объек­ та N SValue, содержащего значение типа CGRect (прямоугольника, по контуру которого было обрезано изображение). Листинг 13.11 показывает реализацию метода im a g eP ic k e r C o n t r o l le r id id F in is h P ic k in g lm a g e : e d it i n g ln f o : . Метод про­ сто создает представление с переданным изображением и добавляет это представление в качестве дочернего к представлению главного контрол­ лера. Он также скрывает контроллер представления выбора изображения с помощью вызова метода d ism issM o d a lV iew C o n tro llerA n im a ted :. Листинг 13.11. Обработка успешного выбора изображения в приложении для работы с камерой -

(void) imagePickerController:(UllmagePickerController *■)picker d idFinis’ n Pickinglmage: (Ullmage *)image editinglnfo:(NSDictionary *)editinglnfo

{ UllmageView *imgView = [[UllmageView alloc} initwithlmage:image]; [eel£.view addSubview:imgView] ; [self dismissModalViewControllerAnimatedrYES] ; (picker release]; (imgView release];

) Листинг 13.12 демонстрирует обработку события, при котором пользо­ ватель отменяет выбор изображения. Мы просто скрываем представление выбора изображения и высвобождаем его. Листинг 13.12. Обработка пользовательской отмены выбора изображения в при­ ложении для работы с камерой - (void) imagePiс kerCont rollerDidCancel: (UllmagePickerController *)picker

{ [self dismissModalViewControllerAriimated:YE$]; (picker release];

) @end

353

Ниже изображен главный экран, который пользователь видит сразу после запуска приложения (рис. 13.4), а также представление, где пользо­ ватель делает снимок (рис. 13.5). j _AT&T

7:59 РМ



|



-

i

New Picture Select a Picture

Р и с . 1 3 .4 . Главный экран, которы й видит пользователь при за п у ск е п ри л ож ен и я с п оддерж к ой камеры

Р и с . 1 3 .5 . П редставл ен и е, где п ользователь н аходи тся в п р о ц ессе п рои зв одства снимка

354

Далее приведено представление, где пользователь только что сделал сни­ мок и представление выбора изображения все еще активно (рис. 13.6). Поль­ зователь может подтвердить, устраивает ли его данный снимок (после чего изображение сохранится, а пользователь увидит главное окно приложения (рис. 13.7)), или нажать Retake (Переснять), чтобы сделать другой снимок. ^АТ?
7;5$РМ

|££

Р и с. 13.6. Представление сразу после того, как пользователь сделан снимок (представление выбора изображения все еще активно)

Г

7:5?РМ

| 3^

Р ис. 13.7. Представление выбора изображения, сохраняющее снимок

355

Ниже показано представление, когда выбор изображения закончился и управление вернул ось к нашему коду (рис. 13.8), а также представление, кото­ рое видит пользователь при выборе существующего изображения (рис. 13.9), .^...АТАТ ?

7.5GPM

I ЭЙ

Р и с . 1 3 .8 . П редставление, когда вы бор и зображ ен и я зак он чен и у п р а в л ен и е возвращ ен о главном у ок н у .j— AT&T

7:59 РМ

■■■■■.- Ш & 35

Р и с . 1 3 .9 . П редставл ен и е, к оторое ви ди т п ользователь при в ы бор е сущ ествую щ его и зо б р а ж ен и я

356

13.6. Резюме В разд. 13.1 вы научились использовать акселерометр. Вы узнали, как получать от него информацию с данной частотой обновления и рас­ познавать ориентацию устройства, а также специфические движения. В разд. 13.2 вы научились проигрывать короткие звуковые файлы и настраи­ вать таймер на выполнение периодических задач. В разд. 13.3 вы научились воспроизводить видеофайлы, из разд. 13.4 узнали, как получать необходи­ мую информацию об устройстве. В разд. 13.5 вы научились использовать камеру для производства снимков. Вы узнали, что прямой доступ к каме­ ре или библиотеке фотографий отсутствует, поэтому требуется использо­ вать предоставленный контроллер (U llm a g e P ic k e r C o n tr o lle r ), ко­ торый обрабатывает взаимодействие с пользователем при производстве и редактировании снимков. Контроллер предоставляет конечный вариант изображения после того, как пользователь закончит работу с ним. Тот же контроллер используется для выбора изображений, хранящихся в библио­ теке. Мы рассмотрели основные понятия с помощью приложения, позво­ ляющ его пользователю производить снимки либо выбирать из уже суще­ ствующих.

Приложение А Сохранение и восстановление состояния программы

В один м омент времени м ож ет бы ть запущ ено тол ько одно при лож е­ ние, поэтом у ваш а програм ма долж на давать пользователю ощ ущ ение, что она активна все время, даж е когда он н аж и м ает кн опку Ноте (В озврат). Д л я этого ваш е прилож ение долж н о сохран ять текущ ее со сто ян и е (н а­ пример, какой уровень иерархии показы вается в дан н ы й м омент, текущ ий термин поиска и т. д.), когда програм м а заверш ается, и восстан авли вать это состояние, когда она запускается повторно. Сущ ествует несколько путей, с помощ ью которы х м ож но оперировать информацией о состоянии, например, использовать базу данны х S Q L ite или обычные фай.™ . О днако больш е всего д л я данной ситуации подходит спи­ сок свойств, который является предметом рассм отрения при лож ен и я А. Чтобы использовать список свойств д л я сохранения/восстановления со­ стояния прилож ения, нуж но следовать приведенны м ниж е рекомендациям: • представить состояние в виде словаря и л и м ассива; • элементы состояния могут быть экзем плярам и типов N S D ic tio n a r y , N SA rray, N SD ata, N S D ate, NSNumber и N S S t r in g ; • добавьте элем енты состоян и я в словарь ли бо м ассив; • сериализуйте словарь или м ассив в объект N S D ata, и сп о л ьзу я метод класса N S P r o p e r t y L i s t S e r i a l i z a t i o n ; • объект N SD ata представляет и н ф орм ац и ю о состоян и и л и бо в ф ор­ м атах X M L, л и бо бинарном; д л я эф ф екти вн о сти и сп о л ьзу й те бинар­ ный формат; • чтобы восстановить состояние, загрузи те зап и сан н ы й файл в объект N SD ata и используйте м етод класса N S P r o p e r t y L is t S e r i a l i z a t i o n д л я получен ия сл оваря и л и м ассива. Р ассм отрим прим ер со х р а н ен и я/во сстан о вл ен и я состо ян и я п рилож е­ ния, используя список свойств. Д опустим, состояние прилож ен и я сохраня­ ется в словарь. Этот словарь содерж ит п ять элементов: два ти п а N S S tr in g , один ти п а NSNumber, один ти п а N S A rray и оди н ти п а N S D a te. Л и сти н г А.1 показы вает м етод делегата п ри л ож ен и я, дем онстриру­ ющ ий концепцию списков свойств. М етод создает объект со сто ян и я при-

358

ложения (словарь) и вызывает saveA p p S tate для сохранения состояния и r e s t o r e S t a t e для восстановления. Листинг А. 1. Метод делегата, используемый при составлении объекта состояния при­ ложения, его сохранении и последующем восстановлении с помощью списка свойств -(void) applicationDidFinishLaunching: (UIApplication *)application { // составляем объек т свойств state = [[NSMutableDictionary alloc] initWithCapacity:5]; [state setObject:@"http://www.thegoogle.com" forKey:@"URL"]; [state setObject:0"smartphones" forKey: SEARCHJTERM"]; [state setObject:[NSNumber numberWithFloat:3.14] forKey:®"PI"]; [state setObject: [NSMutableArray arrayWithObjects:©“Apple iPhone 3G", @"Apple iPhone", @"HTC Touch Diamond", nil] forKey:@“RESULT"]; [state setObject:[NSDate date] forKey:<3"D A T E "]; // сохраняем состояние приложения [self saveAppState]; // восстанавливаем состояние приложения [eelf restoreState];

) Листинг A.2 демонстрирует метод saveAppState. Последний использу­ ет метод dataFrom PropertyL ist: format le r r o r D e sc r ip tio n : класса N S P r o p e r ty L is tS e r ia liz a tio n , чтобы получить объект NSData сериа­ лизованного словаря. Вы можете использовать два формата — бинарный, за­ даваемый с помощью N SP ropertyL istB inaryF om at_vl_0, и XML, опре­ деляемый посредством NSPropertyListXMLFormat_vl_0. Вы также можете передать ссылку на объект NSString» который можно использовать для возвра­ та ошибки. При возникновении ошибки вы должны высвободить этот объект. Получив объект NSData, можете записать его в локальный файл. Листинг А.2. Сохранение состояния приложения в список свойств -(void) saveAppState{ NSString *theError; NSData *theData - [NSPropertyListSerialization dataFromPropertyList:state format :NSPropertyListXMLFormat_vl_0 errorDescript ion:&theError]; i f ( theData}{ NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent :©"Documents/state*plist"]; [theData writeToFile:fileName atomically:YES);

} else{ NSLog(§"Error saving app state; %§", theError); [theError release]; //требуется высвободить

)

)

Листинг A.3 показывает содержимое XML-файла s t a t e . p l i s t , ис­ пользуемого для сохранения состояния приложения. Количество байтов, используемых для сохранения состояния в XML-формате, — 543, тогда как бинарный формат занимает 204 байта.

359

Листинг А.З. Список свойств в XML-формате < ? xml v e r s i o n = "1.0" e n c o d i n g s "U T F - 8 " ?> < 1DOC TY P E p l i s t P U B L I C ■ - / / A p p l e / / D T D P L I S T 1 . 0 / / E N * "ht t p :/ /w w w .a p p l e .c o m / D TD s /P r o p e r t y L i s t - 1 . 0 . d t d " > < p l i s t v e r s i o n ^ "1.0"> < d ict> DATE < d a t e > 2 0 0 8 - 0 9 - 0 4 T 1 7 :47:2 8 Z < / d a t e > PI < r e a b > 3 .1400001049041748 < k e y > R E S U L T < /k e y > <arr a y > <string>Apple iPhone 3G <string>Apple iPhone < s t r i n g > H T C To u c h D i a m o n d < / s t r i n g > < /array> < key > S E A R C H _ T E R M < / k e y > < s t r i n g > s m a r t p h o n e s < /s t r i n g > URL <string>http://thegoogle.com

Л и сти н г A.4 дем онстрирует метод, используемый д л я восстановления состояния прилож ения. С начала файл счи ты вается в объект N S D a ta с по­ мощью методов, описанны х в гл. 9. П осле этого и сп ол ьзуется метод клас­ са p r o p e r ty L is tF r o m D a ta r m u ta b ility O p tio n : f o r m a t : e r r o r : d e s c r i p t i o n : д л я получения объекта словаря. П арам етр m u t a b i l i t y O p tio n прим еняется д л я указания изменяемости возвращ аем ы х объек­ тов. Е сли вы укаж ете N S P r o p e r t y L is t Im m u ta b le , то словарь, как и все записи в нем, возврати тся как неизменяемый. Е сл и вы устан о ви те N SPro p e r t y L i s t m u t a b le C o n t a i n e r s A n d L e a v e s , то словарь и все его записи будут созданы как изм еняем ы е объекты. П арам етр N S P r o p e r t y L is t M u t a b l e C o n t a i n e r s , который мы будем использовать, создает изм еняем ы е объекты только д л я словарей и массивов. Листинг А.4. Восстановление состояния приложения из списка свойств -{void) re s t o r e S t a t e { N S S t r i n g *theError; N S P r o p e r t y L i s t F o r m a t format; N S S t r i n g * f i l e N a m e = [ N S H o m e D i r e c t o r y () s t r i n g B y A p p e n d i n g P a t h C o m p o n e n t : D o c u m e n t s / s t a t e , p l i s t "]; N S D a t a * t h e D a t a = [[ NSD a t a alloc] initWithContentsOfFile:filename]; if(theData){ [state r e l e a s e ] ; state = [NSPropertyListSerialization p r o p e r t y L i s t F r o m D a t a :t h e D a t a mutabilityOption:NSPropertyListMutableContainers f o r m a t :&for m a t e r r o r D e s c r i p t i o n :&t h e E r r o r ]; if (state){ [state r e t a i n ] ;

else{ N S L o g ( @ “E r r o r r e t r i e v i n g a p p state: %@", theEr r o r } ; [theError r e l e a s e ] ; // т р е б у е т с я в ы с в о б о д и т ь

} ttheData release);

) )

360

Приложение Б Запуск внешних программ

Ваше iPhone-приложение может программно вызывать другие iPhoneпрограммы. Более того, вы можете открыть свое iPhone-приложение, что­ бы оно могло быть запущено другой iPhone-программой. Для этого вам требуется указать новую URL-схему в упаковке приложения, а система за­ регистрирует эту схему, как только программа будет установлена. Чтобы запустить другое iPhone-приложение, используйте метод

openURL: экземпляра UIApplication, которому передайте URL этого приложения. Следующий фрагмент кода откроет приложение Maps и по­ кажет заданный адрес: NSString *address = @ "http://maps.google.com/maps?q=plano,tx" ; NSURL *myURL = [NSURL URLWithString:address]; [[UIApplication sharedApplication] o penURL:m y U R L ];

Чтобы зарегистрировать новую URL-схему, нужно добавить ее в файл I n f o . p i i s t. Ниже изображено, что следует добавить, чтобы зарегистри­ ровать новую URL-схему lo o k u p (рис. Б.1.); URL i d e n t i f i e r может быть любой уникальной строкой. ▼URL types

(1 item) (2 items)

▼Item 1 URL dentifier

com.mycompany.lookup

▼URL Schemes

(1 item)

Item 1

lookup

Рис. Б .1. Добавление повои URL-схемы в файл Info.plist

Чтобы в действительности запустить приложение, нужно реализовать метод делегата приложения a p p l i c a t i o n : handleO penU R L :, объявлен­ ный следующим образом: —(BOOL) application:(UIApplication Mapplication handleOpenURL:(NSURL *)url

361

Вы получаете экзем пляр NSURL, ин капсулирую щ и й U R L , использу­ емый при вызове. Вы м ож ете исп ользовать м нож ество м етодов NSURL для производства запросов, парам етров и ф рагм ентов. Н ап рим ер, наш у схему lo o k u p мож но вы звать с использованием почтового индекса л и бо н азва­ ния города. Д л я пои ска по почтовом у индексу требуется вы звать п рило­ жение посредством l o o k u p : / /w w w ? z ip # 6 8 5 0 8 , а д л я вы зо ва с помощ ью названия города — l o o k u p : / / w w w ? c i t y # L i n c o l n . Л и сти н г Б.1 показы вает реали зацию обработки U R L -схемы lo o k u p . Д ля вы п олн ен ия запроса м ы используем м етод q u e r y к ласса NSURL. Это может бы ть c i t y л и бо z i p . Д л я и звл ечен и я ф рагм ен та м ы используем метод f r a g m e n t . П ри веденная ниж е р еал и зац и я дем он стр и р у ет важ ны е части вы зова посредством U R L . Е сли вы не м ож ете обработать запрос, то возвращ аете N0, иначе вы обслуж иваете его и возвращ аете YES. Листинг Б.1. Реализация обработки URL-схемы lookup -(BOOL)application: ( U I A p p l i c a t i o n * ) a p p l i c a t i o n h a n d l e O p e n U R L :(N S U R L *)u r 1{ NSString *q u e r y = [url q u e r y ] ; NSString * f r a g m e n t = [url f r a g m e n t ] ; N S M u t a b l e S t r i n g *0u t p u t ; i f ( [ q u e r y i s E q u a l T o S t r i n g z i p " ] ){ output = [NSMutableString stringWithFormat:@"Looking up by

zip code

% @ " , fragment];

} else

i f { [ q u e r y i s E q u a l To S t r i n g : @ " c i t y " ]){ output = [NSMutableString s t r i n g W i t h F o r m a t L o o k i n g up by city

} e l s e r e t u r n NO; t e x t V i e w . t e x t = output; r e t u r n YES;

}

%@",

fragment];

Ссылки и библиография

[ 1] http://geocoder.ibegin.com/downloads.php. [2] ZIP code: http://en.wikipedia.org/wiki/ZlP code. [3] B’Far, R, Mobile Computing Principles: Designing and Developing Mobile Applications with UML and XML, Cambridge University Press, 2004. [5] Beam, M and Davidson, JD, Cocoa in a Nutshell: A Desktop Quick Reference, O ’Reilly, 2003. [6] Brownell, D, SAX2, O’Reilly, 2002. [7] Davidson, JD , Learning Cocoa with Objective C, 2nd edition, O’Reilly, 2002 .

[8] Duncan, A, Objective-C Pocket Reference, 1st edition, O’Reilly, 2002. [9] Garfinkel, S and Mahoney, MK, Building Cocoa Applications: A Stepby-Step Guide, 1st edition, O’Reilly, 2002. [10] Hillegass, A, Cocoa® Programming for Mac® OS X, 3rd edition, Addison-Wisley Professional, 2008. [11] Kochan, S, Programming in Objective-C, Sams, 2003. [12] M ott, T, Learning Cocoa, O’Reilly, 2001. [13] Owens, M, The Definitive Guide to SQLite, Apress, Inc., 2006» [14] Tejkowski, E, Cocoa Programming for Dummies, 1st edition, For Dummies, 2003. [15] Williams, E, Aviation Formulary V1.43: http://w illiam s.best.vwh.net/ avform.htm. [16] Collections Programming Topics for Cocoa, Apple Reference Library. [17] Document Object Model (DOM): http://w w w .w 3.org/TR/D O M Level-2-Core/. [18] Exception Programming Topics for Cocoa, Apple documentation. [19] Introduction to the Objective-C 2.0 Programming Language, Apple documentation. [20] Key-Value Coding Programming Guide, Apple documentation. [21] libxml2: The XML С parser and toolkit: http://xm lsoft.org/. [22] Threading Programming Guide, Apple Reference Library. [23] The XML standard: http://www.w3.org/TR/REC-xml.

363

Алфавитный указатель

#import. 20

finally, 36

#indude, 20

throw, 36 try, 37

A alloc, 23 AudioServicesCreateSystemSoundl D (), 345

G GPS, 317

AudioScrvicesDisposcSystemSouncllD(), 345 AudioServicesPlay System Sound(). 345

1 id, 21

С CGPoint, 90

Info.pl ist, 361

CGPointMake, 85

К

CGRect, 84

KVC, 43

CGRect Make. 91 CGSize, 91

L

CGSizeMake, 91

libxm!2

class, 19

charactersSAXFunc(), 309 xmlChildrenNodc, 300

CLLocation, 318 altitude, 320

xml DocGet Root Blement(), 298

coordinate, 320 horizontal Accuracy. 320

xmlNode, 298 xmlNodeListGct String, 302

timestamp» 321

xmlStrcmpO, 300

vertical Accuracy, 320 CLLocationManager, 318

M

CLLocationManagerDelegate, 319

MPMoviePlayerController, 347

desiredAccuracy, 318

MVC, 143

distanceFilter, 318 startUpdatingLocation, 319 stop U pdati ngLocation, 319 copyWithZone:, 66

N nil, 22 Nill, 21 NSArray, 58

D

arrayWithObjects:, 60,68

dealloc, 26

copy, 64

dynamic, 30

NSMutableArray, 58

E

objectAtlndex:, 63 sortedArrayUsingSelector, 72

exception catch. 36

NSAutoreleasePool, 24 NSBundle. 270

NSCopying, 66

anyObject. 75

NSData

containsObject:. 75

dataW ithContentsO fFile:, 270

intersectsSet:, 75

\vriteToFile:atomkally:, 290

isSubsctOfSet:, 75 NSMutableSet, 76

NSDictionary, 78 all Keys, 79

NSString. 22

allValues.80

cStri ngUsi ng E ncod ing:, 298

dictionary WithObjectsAndKeys:, 79

NSM utableString, 22

is EqualTo Dictionary:. 80

strmg\VithCwlcf>L4()^Rljcnc:odingXTri)n, 297

koysSori ccl By Value UsingSelector, 80

N SU RL 362

object ForKey:, 79

NULL, 22

NSError, 4 1 NSException, 36 exception WiiliNa!iic:rcason:uscrInfo:. 39

R RSS, 294

raise. 37 N SFileHandle, 258 seekToFilcOfTst’t:. 271 NSFileM anager. 258

S SEL, 22 self. 23

defaultM anager, 259

S Q L 273

enum eratorAtPath:. 259

SQLite, 273

NS1 lom eD irectory(), 258

BLOB, 286

N SIndexPath, 217

sqlite3_close(), 274

row, 218

sqlite3_coluinn_XXX(). 281

scction, 218

sqlite3_create_ lunction(), 283

N SInteger. 70

sqlite3_execO> 279

N SlnvocationO peration, 50

sqlite3_finalize<), 280,282

NSM utableArray. 58

sqlite3_Jrce(), 276

removeObject:, 65 N SM utableD ict ionary. 78

sqlite3_malloe(), 275 sqlite3_prepare_v2(), 279

add EntriesFrom Dictionary:. 80

sqlite3_rc5ult_error(). 284

removeObject ForKey:, 79

sqlitc3_rcsull_XXX(), 286

N SM utableSet, 75

sqlitc3_step(), 281

addO bject. 76

sqlite3jvalue, 285

removeObject:, 76

sqlite3_valu
unionSet:. 76 NSNull, 48 NSObject. 22

SQLITE_DONE, 280 SQLITE_RO W , 280 synthesize. 29

alloc, 23 conformsToProtocol:. 28 dealloc, 2G

UI Accelerometer

init, 23

delegate, 353

poseAsClass:, 36

shared Accelcrometer, 342

release, 25 N SO peration, 50 NSPropertyListSerialization, 358

updatelnterval, 344 UIAccelcrometerDelegatc, 342 Accelerometerxlid Accelerate:, 342

N SSelectorFrom StringO. 22

UI ActionSheet. 192

NSSet. 74

UIAlertView, 190

dequeueReusablcCell Withldentifier:. 217 sctEditing:animated:, 223

UIApplication open URL:, 361 send ActionsForControl Events:, 124 UIButton. 135 buttonWithType ,135 UlControl. 122 control Events, 124 enabled, 123 highlighted, 123

tableView:canMoveRowAtIndexPath:, 236 UlTableViewDataSource, 216 UITableViewStylePlain, 216 UITableViewCell, 215,219 image, 220 UITableViewDelegate, 215 UlTextField, 126 UlTextField Delegate, 131

selected, 123 state, 123

UITextlnputTraits, 126

UIDatePicker, 141

UITextView, 186

U ID evice,347

UlTouch, 97

model, 348

U lV iew

orientation, 348

beginAnimations: 114

systemName, 348 systemVersion, 348

commitAnimations, 116 locationlnView:, 98

uniqueldentifier, 348

previousLocationlnView:, 98 tapCount, 98

UIEvent, 98 allTouches, 98

UlViewController, 143 dismissModalViewControllerAnimated:, 153 initWithNibName:bundle:, 144

Ullmage imageNamed:, 153

interfaceOrientation, 144

UllmagePickerController, 349

leftBarButtonltem, 168

isSourceTypeAvailable:, 349 UIImagePickerControllerDelegate, 349

loadView, 147

UINavigationController, 156

modalViewController, 171

UINavigationltem, 166

navigationltem, 166

UlPageControl, 140 UlPickerView, 177

parentViewController, 171 presentModalViewControllenanimated:, 171 rightBarButtonltem, 168 shouldAutorotateToInterfoceOrientatioa*, 144

компонент, 177 ряд, 177

tabBarltem, 151

UlResponder, 98 touchesBegan:withEvent:, 99 touchesCancelled:withEvent:, 99 touchesEnded:withEvent:, 99 touchesMoved rwithEvent:, 99

UlW ebV iew , 193 stringByEvaluatingJavaSmptFromString:, 205 UIW ebViewDelegate, 208

UlScreen, 91

X

UlSegmentedControl, 137

XML, 292

UlSlider, 133

DOM, 296

continuous, 133

RSS, 294

maximumValue, 133

SAX, 302

minimum Value, 133 U lSw itch, 134 UlTabBarltem, 151 badge Value, 151 UITableView, 215 dataSource, 216

А Акселерометр, 340 Анимация, 113

С Свойство, 29 assign, 29 сору, 29

Б Бросить исключение. 37

dynamic, 29 getter, 30

В Вибрация, 345

nonatomic, 29 readonly, 29 setter, 30

Высвободить, 26

synthesize, 30 Сообщение, 19

Г

Список свойств, 358

Геокодирование, 317

Статический, 19 Супер, 27

3

Счетчик захватов» 24

Захват, 24 Т

И Исключения, 36

Табличное представление, 214

Ц

К Камера, 351 Категория, 34 Класс, 20 методы, 20 объект, 20 Кодирование «ключ-значение*, 42 М Многопотоковость, 50 Модальный контроллер представления, 170 П Панель закладок, 149 Позиционирование, 35 Представление, 90 геометрия, 90 границы, 94 дочерние представления, 96 родительские представления, 96 фрэйм, 93 центр, 94 Протокол, 26 необязательный, 27 обязательный, 27 Р Радиоинтерфейс, 149

«Цель-действие», 123

Производственно-практическое издание

Али М а х е р П Р О ГР А М М И Р О В А Н И Е Д ЛЯ IPHONE

Директор редакции Л. Бершидский Ответственный редактор В. Обручев Художественный редактор С. Лебедева ООО «Издательство «Эксмо» 127299, Москва, ул. Клары Цеткин, д. 18/5. Тел. 411-68-86,956-39*21. Home раде: www.eksm o.ru E-mail: lnfoQ eksm o.ru Оптовая торговля книгами -Эксмо*: ООО -ТД -Эксмо». 142700. Московская обл.. Ленинский p-и. г. Видное, белокаменное ш., д, 1. многоканальный тол. 411-50-74, E-mail: receptloneekamo-eate.ru

По вопросам приобретения книг «Эксмо» зарубежными оптовыми покупателями обращаться в огдол зарубежных продаж ТД -ЭксмоE-mail; lntematloflal9eksinD-aale.ru In te rn a tio n a l Sates; International wftotesato customers shoutt contact Foreion Safes Department o f Tradino House •E k s n w tor thoir orders.

lntemat*onal»eksmo-eale.ru

По вопросам м х а м книг корпоративным клиентам, а том числа а специальном оформ­ лении, обращаться по тел. 411-66-59доб. 2115. 2117. 2118. E-mail: vipzakazOeKsmo.ru Оптовая торговле бумаяно-белоаыми и канцелярскими товарами для школы и офиса •Канц-Эксмо»: Компания «Канц-Эксмо»: 142702, Московская обл.. Ленинский р-н. г. виднов-2. Белокамеююе ш., д. 1, а/я 5. Тел./фале +7 (495) 745-28-87 (многоканальный). е-таИ: kancOeksmo-salo.ru, сайт: www.kanc-eksmo.ru

Полный ассортимент книг издательства «Э*смо» для оптовых покупателей: В Санкт-Петорбурге: ООО C3K0. пр-т Обуховской Обороны, д. 54Е. Тел. (612) 365-46*03/04. В Нижнем Новгороде: ООО ТД «Эксмо НН». ул. Маршала воронова, д. 3. Тол. (В312) 72-36-70. В Казани: Филиал ООО «РДЦ-Самара». ул. Фрезерная, д. 5. Тел. (843) 570-40-45/46. В Ростове-на-Дону: ООО -РДЦ-Ростоо», пр. Стачки. 243А. Тел. (863) 220-19-34. В Самаре: ООО «РДЦ-Самара», пр-т Кирова, д. 75/1, литера «Е>. Тел. (646) 209-66-70. В Екатеринбурге: ООО -РДЦ-Екатеринбург». ул. Прибалтийская, д. 24а. Тел. (343) 378-49-45. В Киеве: ООО ■РДЦЭксмо-Украина». Московский пр-т. д. 9. Тел./факс (044) 495-79-80/61. Во Львове: ТП ООО *Эксмо-Залвд>, ул. Буэкова. д. 2. Тел./факс (032) 24S-00-19. В Симферополе: ООО «Эксмо-Крым», ул. Киевская, д. 153. Тол./факс (0652) 22-90-03,54-32-99. В Казахстане: ТОО «РДЦ-Алматы». ул. Домбровского, д. За. Тел./факс (727) 251-59-90/91. rdc-almaty^maii.ru

Полный ассортимент продукции издательства <Зксмо>; В Москве в сети магазинов «Новый книжный*: Центральный магазин — Москва, Сухарооскаи пл., 12. Тел. 937-85-81. Волгоградский пр-т, д. 78, тел. 177-22-11:ул. Братиспппсквя.д. 12.Тел. 346-99-95, Информация о магазинах «Новый книжный» по тел. 780-58-81. В Санкт-Петербурге в сети магазинов «Буквоед-:

•Магазин на Новсхом». д. 13. Тел. (812) 310-22-44.

Подписано в печать 15.07.2010. Формат 70x100VieПечать офсетная. Уел. печ. л. 29,81 • Тираж 1500 экз. Заказ № 5837 Отпечатано с готовых файлов заказчика в О А О «ИПК «Ульяновский Д о м печати». 432980, г. Ульяновск, ул. Гончарова, 14

ISBN 978-5-699-40764-4

fulfill

Э'ТвббЭЭ1407644">

Recommend Documents

Approfondimenti tematici iPhone PROGRAMMING Il corso completo per imparare facilmente a programmare lo smartphone Appl...

iPhone ™ FOR DUMmIES ‰ 3RD EDITION iPhone ™ FOR DUMmIES ‰ 3RD EDITION by Edward C. Baig USA TODAY Perso...

%'SQTPIXI'SYVWIMRM4LSRI ERHM4SHXSYGL4VSKVEQQMRK &IKMRRMRK M4LSRI(IZIPSTQIRX )\TPSVMRKXLIM4LSRI7(/ (EZI1EV...

Beginning iPhone Development Exploring the iPhone SDK DAVE MARK JEFF LAMARCHE Beginning iPhone Development: Exploring...

[email protected] http://www.springeronline.com [email protected], http://www.apress.com/info/bulksales http:...

eload 24 iPhone 4 – K0mmunikation Klicken, Lesen, Weitermachen. So einfach geht das. Rubrik Thema Umfang eBook Autor ...

Prepared exclusively for Vadim Kudria Download at WoweBook.Com What Readers Are Saying About iPhone SDK Development ...

Pogue Macintosh/Windows iPhone The Missing Manual Coverage includes: The phone and organizer. Sophisticated features...