Más contenido relacionado
La actualidad más candente (16)
Similar a RFC Viewer開発を通して学ぶ!! iOS開発のパターン化 (20)
RFC Viewer開発を通して学ぶ!! iOS開発のパターン化
- 5. • Mac OS XのCocoaの機能縮小版。ただ
し、独自のUIや改良個所があるので、
単なるサブセットでない。
• 使用禁止APIがあるが、C言語によるネ
イティブ開発が行える。
• iOSはUNIX系のOSで、32bit/64bit対応。
- 12. 形式プロトコル
@protocol Playable
- (void)play;
- (void)stop;@end
プロトコル名
プロトコルの採用
#import Cocoa/Cocoa.h
#import “Playable.h”
@interface Song : NSObject Playable {
id title;
プロトコル準拠の確認
}
- (id)title;
- (void)setTitle;@end
if ([song conformsToProtocol:@protocol(Playable)]) {
[song play];
}
else {
}
- 14. メモリ管理
/* 生成(retain) */
NSString *title = [[NSString alloc] initWithString:@”hello”];
/* 解放 */
[title release];
/* autorelease */
for (;;) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *s1 = [[NSString alloc] initWithString:@”hello”];
[s1 autorelease];
NSString *s2 = @”hello”;
NSString *s3 = [NSString stringWithString:@”hello”];
[pool release];
}
- 16. Xcode 5 から @import が利用できるよう
になった。(Modules)
例)
@import UIKit;
@import UIKit.UIView;
- 17. Objective-C 2.0以降のクラス実装のパターン
@interface Document : NSObject!
@property (strong, nonatomic) NSString *version;!
!
- (id)init;!
- (void)dealloc;!
@end!
プロパティを利用
!
@interface Document ()!
@property (strong, nonatomic) NSString *text;!
- (void)_init;!
@end!
プライベート宣言はク
ラス拡張で
!
@implementation Document!
!
@synthesize version = _version;!
@synthesize text = _text;!
!
- (id)init!
{!
self = [super init];!
if (self) {!
[self _init];!
}!
return self;!
}!
!
- (void)dealloc!
{!
self.version = nil;!
self.text = nil;!
}!
!
- (void)_init!
{!
_version = @”1.0”;!
_text = @”This is a pen.”;!
}!
!
@end!
ARC有無に関わらず汎用的に
使える
- 18. 宣言済みプロパティ
@property (nonatmic) NSString *value;
- (NSString *)value;
- (void)setValue:(NSString *)newValue;
同等
@synthesize value = _value;
@interface MyClass : NSObject
@property (nonatmic) NSString *_value;
@end
@implementation MyClass
- (NSString *)value { return _value; }
- (void)setValue:(NSString *)newValue
{
[_value release];
_value = [newValue retain];
}
@end
自動に宣言
ARCなしの場合は
こんな感じ?
- 19. プロパティ
@interface Song : NSObject {
id _title;
}
- (id)title;
- (void)setTitle:(id)title;
@end
@implementation Song
- (id)title
{
return _title;
}
- (void)setTitle:(id)title
{
[title release];
_title = [title retain];
}
@end
@interface Song : NSObject
@property (strong, nonatmic) NSString *title;
@end
@implementation Song
@synthesize title = _title;
@end
プロパティを利用すれば、
ARCの利用有無に関わらず、
同じ記述が出来る。
- 33. 通知センター
/* 通知元 */!
NSString
*ConnectorDidBeginRfc = @ConnectorDidBeginRfc;!
!
!
[[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidBeginRfc!
object:self userInfo:userInfo];!
!
!
/* 受信メソッドの登録 */!
[[NSNotificationCenter defaultCenter] addObserver:self!
selector:@selector(_connectorDidBeginRfc:) !
name:ConnectorDidBeginRfc!
object:nil];!
!
!
/**!
* 受信メソッド!
*/!
- (void)_connectorDidBeginRfc:(NSNotification*)notification!
{!
RFCResponseParser *parser;!
parser = [[notification userInfo] objectForKey:@parser];!
!
...!
}!
- 34. キー値監視
/* Connectorの networkAccessingキーを監視 */!
[[Connector sharedConnector] addObserver:self!
forKeyPath:@networkAccessing!
options:0!
context:NULL];!
!
!
/* 値の変更を受信 */!
- (void)observeValueForKeyPath:(NSString*)keyPath!
ofObject:(id)object!
change:(NSDictionary*)change!
context:(void*)context!
{!
if ([keyPath isEqualToString:@networkAccessing]) {!
[self _updateNetworkActivity];!
}!
}!
!
!
/* 通知 */!
[self willChangeValueForKey:@networkAccessing];!
[self didChangeValueForKey:@networkAccessing];!
- 35. デリゲート
/* プロトコル */!
@protocol RFCResponseParserDelegate NSObject!
- (void)parser:(RFCResponseParser*)parser didReceiveResponse:
(NSURLResponse*)response;!
@end!
!
!
/* デリゲートのメソッドを呼び出す */!
if ([self.delegate respondsToSelector:@selector(parser:didReceiveResponse:)]) {!
[self.delegate parser:self didReceiveResponse:response];!
}!
- 36. Blocks
/* Blocks定義 */!
typedef void (^RFCResponseParserCompletionHandler)(RFCResponseParser *parser);!
!
!
/* 要求メソッドでBlocksを受け取る */!
- (void)rfcIndexWithCompletionHandler:(RFCResponseParserCompletionHandler)completionHandler;!
!
!
!
/* Blocksの呼び出し */!
if (parser.completionHandler) {!
parser.completionHandler(parser);!
}!
!
!
/* Blockの生成 */!
__block MasterViewController * __weak blockWeakSelf = self;!
[[Connector sharedConnector] rfcIndexWithCompletionHandler:^(RFCResponseParser *parser) {!
MasterViewController *tempSelf = blockWeakSelf;!
if (! tempSelf) return;!
!
[Document sharedDocument].indexArray = parser.indexArray;!
[tempSelf _updateSectionIndexArray];!
[tempSelf.tableView reloadData];!
}];!
- 45. アプリのデリゲート
通信中インジケータ
@implementation AppDelegate- (BOOL)application:(UIApplication *)application
willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/*
ConnectのnetworkAccessingキーを監視 */
[[Connector sharedConnector]
addObserver:self
forKeyPath:@networkAccessing
options:
0
context:NULL];
return YES;}(void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context{
/* networkAccessingキーに変化あり */
if
([keyPath isEqualToString:@networkAccessing]) {
[self
_updateNetworkActivity];
}}- (void)_updateNetworkActivity{
/* 通信中な
らインジケータを表示 */
[UIApplication
sharedApplication].networkActivityIndicatorVisible
= [Connector
sharedConnector].networkAccessing;}@end
真:表示
偽:非表示
ココ
- 46. 通信開始
- (void)parse{
DBGMSG(@%s, __func__);
NSString
*urlString = nil;
/* 通信先 */
if (self.index == 0) {
/* 目次文書 */
urlString = [Document sharedDocument]
.indexUrlString;
}
else
{
/* 指定された番号のRFC文書 */
urlString = [[Document sharedDocument]
rfcUrlStringWithIndex:self.index];
}
/*
URLからNSURLRequestのインスタンスを生成 */
NSURLRequest
*urlRequest = nil;
if
(urlString) {
NSURL
*url;
url =
[NSURL URLWithString:urlString];
if (url)
{
urlRequest = [NSURLRequest
requestWithURL:url];
}
}
DBGMSG(@%s urlString(%@),
__func__, urlString);
if (! urlRequest) {
/* NSURLRequestインスタンスの生
成失敗 */
self.networkState = kRFCNetworkStateError;
self.error = [self _errorWithCode:
kRFCResponseParserGenericError
localizedDescription:
@NSURLRequestの生成に失敗しました。];
return;
}
/* 受信データの格納バッファの用意 */
self.downloadedData = [[NSMutableData alloc] init];
/
* NSURLConnectionインスタンスの生成
(並列処理の為のキューを設定) */
self.urlConnection =
[[NSURLConnection alloc]
initWithRequest:urlRequest
delegate:self
startImmediately:NO];
[self.urlConnection setDelegateQueue:self.queue];
/*
通信中インジケータの更新 */
[self
willChangeValueForKey:@networkState];
self.networkState
= kRFCNetworkStateInProgress;
[self
didChangeValueForKey:@networkState];
/* 通信開始 */
[self.urlConnection start];}
前のスライド
- 47. 受信データの格納
- (void)connection:(NSURLConnection*)connection didReceiveResponse:
(NSURLResponse*)response{
/* デリゲートに通知 */
if ([self.delegate
respondsToSelector:@selector(parser:didReceiveResponse:)]) {
/* 主スレッドで実行 */
dispatch_async(dispatch_get_main_queue(),
^{
[self.delegate parser:self didReceiveResponse:response];
});
}}(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data{
/* 受信したデータ
をバッファに格納 */
[self.downloadedData appendData:data];
/* デリゲートに通知 */
if
([self.delegate respondsToSelector:@selector(parser:didReceiveData:)]) {
/* 主スレッドで実行 */
dispatch_async(dispatch_get_main_queue(),
^{
[self.delegate parser:self didReceiveData:data];
});
}}
- 48. 通信終了
- (void)connectionDidFinishLoading:(NSURLConnection*)connection{
/* 通信中インジケ
ータの更新 */
[self willChangeValueForKey:@networkState];
self.networkState
= kRFCNetworkStateFinished;
[self
didChangeValueForKey:@networkState];
/* 目次文書 */
if (self.index == 0)
{
/* 受信データのパース */
[self _parseIndexArray];
}
/* 主スレ
ッドで実行させる */
dispatch_async(dispatch_get_main_queue(), ^{
[self
_notifyParserDidFinishLoading];
});
self.urlConnection = nil;}(void)_notifyParserDidFinishLoading{
/* デリゲートに通知 */
if ([self.delegate
respondsToSelector:@selector(parserDidFinishLoading:)]) {
[self.delegate
parserDidFinishLoading:self];
}}
- 49. 通信を要求する
/* 通信中パーサを配列に格納 */
[self.parsers
addObject:parser];
/* 通信中インジケータの更新 */
if
(networkAccessing != self.networkAccessing) {
[self
- (void)rfcWithIndex:(NSUInteger)index
willChangeValueForKey:@networkAccessing];
[self
completionHandler:(RFCResponseParserCompletionHandler) didChangeValueForKey:@networkAccessing];
}
/* 通
completionHandler{
BOOL
信開始を通知 */
NSMutableDictionary *userInfo
networkAccessing = self.networkAccessing;
/* パーサの
= [NSMutableDictionary dictionary];
[userInfo
インスタンスを生成 */
RFCResponseParser
*parser
setObject:parser forKey:@parser];
= [[RFCResponseParser alloc] init];
parser.index
[[NSNotificationCenter defaultCenter]
= index;
parser.queue = self.queue;
parser.delegate =
postNotificationName:ConnectorDidBeginRfc
self;
parser.completionHandler =
object:self userInfo:userInfo];}
completionHandler;
/* 通信開始 */
[parser parse];
if (parser.error) {
/* 通信開始エラー */
NSMutableDictionary *userInfo
= [NSMutableDictionary dictionary];
[userInfo setObject:parser forKey:@parser];
[[NSNotificationCenter defaultCenter]
postNotificationName:ConnectorDidFinishRfc
object:self
userInfo:userInfo];
if (parser.completionHandler)
{
parser.completionHandler(parser);
}
return;
}
- 50. 応答を受け取る
- (void)parserDidFinishLoading:(RFCResponseParser *)parser{
if ([self.parsers
containsObject:parser]) {
[self _notifyRfcStatusWithParser:parser];
}}(void)_notifyRfcStatusWithParser:(RFCResponseParser *)parser{
NSMutableDictionary
*userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:parser
forKey:@parser];
/* 通信完了を通知(通知センター) */
[[NSNotificationCenter
defaultCenter] postNotificationName:ConnectorDidFinishRfc
object:self
userInfo:userInfo];
/* 通信完了を通知(Blocks) */
if (parser.completionHandler)
{
parser.completionHandler(parser);
}
/* 通信中インジケータの更新 */
[self willChangeValueForKey:@networkAccessing];
[self.parsers removeObject:parser];
[self didChangeValueForKey:@networkAccessing];}
- 51. 要求を投げる
- (void)viewDidLoad{
[super viewDidLoad];
if (self.rfc.text)
{
[self configureView];
}
/* RFC文書の取得要求を投げる */
__block
DetailViewController * __weak blockWeakSelf = self;
[[Connector
sharedConnector] rfcWithIndex:[self.rfc.rfcNumber integerValue]
completionHandler:^(RFCResponseParser *parser)
{
/* 応答を受けた際の処理 */
DetailViewController *tempSelf =
blockWeakSelf;
if (! tempSelf) return;
if (parser.rfc)
tempSelf.rfc.text = parser.rfc;
[tempSelf configureView];
}];}