Home

Born Neet

プレゼンのコツは、情熱と練習。スティーブ・ジョブズ 驚異のプレゼン

せっかく読んだ本の内容を忘れちゃわないように、感想をブログに書いておくことにした。(昔もちょっと書いてたけど)
というわけで第1段はこれ。

photo
スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則
カーマイン・ガロ 外村仁 解説
日経BP社 2010-07-15

by G-Tools , 2010/09/23

サブタイトルが「人々を惹きつける18の法則」となっていることもあり、
一見テクニック集かな、と思ったけど全然違った。

プレゼン本というよりは自己啓発本に近いかも、情熱プログラマーみたいな。

プレゼンに一番大事なのは “情熱” 、これは繰り返し述べられている。
ネタバレにならない程度に引用しておくと、

結局、自分が夢中になれないのなら他人が夢中になってくれるはずがないのだ。(P. 213)

聴衆に感銘を与えられるスピーカーになりたいが今の仕事がどうしても好きになれない場合、 仕事を変えることを考えるべきだ。(P. 218)

こんな感じ。
うん、いいこと言うね。2つめとか刺さる。
よせよ、痛いじゃないかね…。

もうひとつ、練習の大切さも強調されている。

聞き手に訴えるのはストーリーである。スライドではない。(P. 22)

ストーリーを語るのはスライドではない。あなたなのだ。(P. 40)

スライドに情報を詰め込んでいる暇があったら練習しろよ、と。

あとこれも当たり前だけど、簡潔さも大事。
ちゃんと理解している人はどんな難解なことでも簡単に説明できるはず。

2分の訓戒
リーダーは簡素化するのが仕事です。今後の方針を2分で説明できなければいけないのです。(P. 173)

『学ぶのに25年もかかったことを5分で教えられるわけがないでしょう』。もちろん、彼には程なくやめてもらったよ」(P. 220)

他にもいろいろといいことが書いてあり、得るものが多かったです。
上では引用するのは避けましたが、スライドを作る際気をつけるべきこと等、実践的なテクニックもちゃんと載っています。

いやぁ、売れている本だから期待してなかったけど、いい本でした。

最後に僕が一番気に入っているところを引用しておきます。
こんなにストレートに言われちゃ、次のプレゼン頑張るしかないですよね。
(強調は僕が付けました。)

ゲイツは難解だがジョブズは明快だ。ゲイツは抽象的だがジョブズは具体的だ。ゲイツは複雑だがジョブズは簡潔だ。
疑問に思う人もいるかも知れない。「ビル・ゲイツはジョブズほど簡潔なしゃべり方をしないかもしれない。でも、世界一の金持ちになった人物だ。それなりにきちんとしたことをしているのではないか。」と。
そのとおりだ。ゲイツはウィンドウズを発明した。世界のコンピューターの90%にインストールされているオペレーティングシステムを発明したのだ。
でもあなたはウィンドウズを発明していない。あれはゲイツだから許されるしゃべり方であり、あなたには許されない。
(P. 209-210)

PR

Macでvsftpd

  • 2010-09-17 (Fri)
  • mac

iPhone/iPadアプリからFTPしたくて、どうすればいいのかなーと調べてたら、
「SimpleFTPSample」なるものをAppleが公開してあっさり解決した

…かと思ったら、僕のmac(10.6 snow leopard)にはFTPサーバがいなくてテストできないことが判明した。
そして自分自身にftpd関連の知識が欠落していることにも気づき愕然とした。

というわけで、macにvsftpd(※)を入れてみることにした。
※ ftpdのデファクトスタンダードが何かすらわかんなかったけど、
 Redhat系で標準な気がするvs(Very Secureの意味なんだ!)ftpdをチョイス。

参考

インストール

手抜きでmacports使います。

sudo port install vsftpd

設定

お次は設定です。sampleをコピーして変更します。

cd /opt/local/etc/ sudo cp -p vsftpd.conf.sample vsftpd.conf sudo vi vsftpd.conf # 匿名禁止 anonymous_enable=NO # ローカルユーザによるログイン・アップロードを許可 local_enable=YES write_enable=YES # asciiモード許可 ascii_upload_enable=YES ascii_download_enable=YES :wq

起動&テスト

sudo vsftpd ps -ef | grep ftp | grep -v grep ftp localhost Trying ::1... ftp: Can't connect to `::1': Connection refused Trying fe80::1%lo0... ftp: Can't connect to `fe80::1%lo0': Connection refused Trying 127.0.0.1... Connected to localhost. 220 (vsFTPd 2.2.2) Name (localhost:test): test 331 Please specify the password. Password: **** 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> bye

できました。

超適当ですがテスト用としては十分でしょう。
※ 必要な時にしか立ち上げないのでセキュリティ面もそんな気にしない感じで。

IB不使用&オープンソースなiPadアプリ(テキストエディタ)を作る 第8回:内蔵ブラウザとメール送信

第8回の今回は、編集中のファイルを
内蔵Webブラウザで表示&メール送信してみます。

当初予定していた目次からどんどん離れていきますが、
まぁいいでしょう。

今回の内容は非常に簡単なのでサクっといきます。

[参考]

基本的には、参考文献(第1回参照)だけで十分でしたが、
1点だけ、Stack Overflowにお世話になりました。
UISegmentedControlをToolbarに入れる時は、UIBarButtonItemでWrapしないといけないんですね…。

[素材]

引き続き、Soft * Accessory様の素材をお借りしています。

1. Webブラウザ

まずは内蔵ブラウザでのプレビュー機能。
UISegmentedControlでSource/Browserを選択して切り替えます。

というわけでやることは、DetailViewControllerのinitでボタンを追加して、
ブラウザを開くメソッドを作るだけです。


		// SegmentedControlの作成
		UISegmentedControl *segment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Source", @"Browser", nil]];
		segment.segmentedControlStyle = UISegmentedControlStyleBar;
		segment.selectedSegmentIndex = 0;
		[segment addTarget:self action:@selector(segmentDidPush:) forControlEvents:UIControlEventValueChanged];

		// Toolbarに入れる為にUIBarButtonでWrap
		UIBarButtonItem *segmentButton = [[UIBarButtonItem alloc] initWithCustomView:segment];
		
		// Toolbarに設定
		NSArray *items = [NSArray arrayWithObjects:flexible, undoButton, redoButton, fixed, leftButton, rightButton, flexible, segmentButton, nil];
		[toolbar setItems:items];
		
		
// SegmentedControlが変化した時に呼ばれる		
- (void)segmentDidPush:(UISegmentedControl *)sender {
	
	// 0ならソース
	if (0 == sender.selectedSegmentIndex) {
		webView_.hidden = YES;
	}
	// 1ならブラウザ
	else if (1 == sender.selectedSegmentIndex) {
				
		[self saveContents];
		[self changeUrl];
		
		webView_.hidden = NO;
	}
	
}


// WebViewでファイルを開く
- (void)changeUrl {

	webViewReloaded = NO;
	
	[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
	
	// <meta charset="UTF-8" />しないと文字化けする
	NSURL *url = [NSURL fileURLWithPath:path_];
	NSURLRequest *req = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
	[webView_ loadRequest:req];

}

これだけでWebViewでローカルファイルを開けます。簡単ですね。
(UIWebViewDelegateを実装して、読み込み完了後にIndicatorを非表示にしてますが、割愛します。)

2. メール送信

次はメール送信、こちらはWebViewでの表示以上に簡単です。
MessageUIフレームワークをimportして、MFMailComposeViewControllerにメール処理をしてもらうだけです。

// DetailVIewController.h

#import <MessageUI/MessageUI.h>

@interface DetailViewController : UIViewController <UIPopoverControllerDelegate, UISplitViewControllerDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate> {
// DetailVIewController.m

		// メールボタン追加
		UIBarButtonItem *mailButton  = [[UIBarButtonItem alloc] initWithTitle:@"Mail" style:UIBarButtonItemStyleBordered target:self action:@selector(mailDidPush)];

		NSArray *items = [NSArray arrayWithObjects:flexible, undoButton, redoButton, fixed, leftButton, rightButton, flexible, segmentButton, fixed, mailButton, nil];
		[toolbar setItems:items];

// メールボタンから呼ばれる
- (void)mailDidPush {
	
	if ([MFMailComposeViewController canSendMail]) {
		MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];

		// delegateじゃなくmailComposeDelegate
		// delegateにするとUINavigationViewControllerDelegateを実装してないって怒られる
		mailViewController.mailComposeDelegate = self;

		// 本文&添付
		NSData *data = [NSData dataWithContentsOfFile:path_];
		[mailViewController setSubject:[path_ lastPathComponent]];
		[mailViewController setMessageBody:textView_.text isHTML:NO];
		// とりあえず全部plain textとして扱っちゃう
		[mailViewController addAttachmentData:data mimeType:@"text/plain" fileName:[path_ lastPathComponent]];
		
		[self presentModalViewController:mailViewController animated:YES];
	}
}

//  処理が終わったら非表示にする
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
	[controller dismissModalViewControllerAnimated:YES];
}

[完成]

いい感じです。
内蔵ブラウザ
メール送信

[まとめ]

いかがだったでしょうか?
だいぶ見栄えもよくなってきたのでは、と自画自賛しています。

まだ細かいバグが残ってるので、
その辺りを調整してリリース申請してみようかと思います。

それでは、次回もご期待下さい。

[コード]

今回のコードは「Edhita8.zip」に入っています。
GitHubのdownloadページからダウンロードして下さい。

Downloads for tnantoka's Edhita - GitHub

IB不使用&オープンソースなiPadアプリ(テキストエディタ)を作る 第7回:AdMob

第7回。

今回は無料アプリの宿命(?)である
お金の問題を解決してくれるかもしれない広告についてです。

まぁお金が欲しければ有料化すればいい話なのですが、
そんな勇気もない僕のような開発者には強い味方ですね。

それでは始めます。

なお、AppleのiAdはまだ日本では表示されないので、
GoogleのAdMobを使います。

参考

参考文献は第1回参照

素材

引き続き、Soft * Accessory様の素材をお借りしています。

1. AdMob登録

まずはAdMobに登録しないと始まりません。

AdMobのサイトにアクセスし、
今すぐスタートから新規登録を行ないます。

ちなみに必要な情報は以下のとおり。
僕はオプションの電話・会社以外ちゃんと入力しました。

  • 電話(オプション)
  • 会社(オプション)
  • 住所
  • 市区町村
  • 郵便番号
  • 言語

必要な情報を入力し「submit」すると、「AdMobアカウントの登録」メールが来ます。
その中のリンクをクリックすると「お客様のアカウントが有効になりました」画面が表示され、
登録は完了です。

2. AdMob SDKへの取得

次にAdMobのSDKをダウンロードします。

ログインするか、ログイン後画面右上のメールアドレスをクリックして、
アカウント画面に行きます。

「サイト及びアプリケーション」内の「サイト/アプリケーションの追加」を
クリックすると、サイト情報の入力画面になります。
「iPadアプリケーション」を選択し、必要な情報を入力します。
※ アプリURLは入力しなくても大丈夫です。

次に進むと「サイト コードを取得」画面が出てくるので、
「AdMob iPad/iPhone SDKをダウンロード」からSDK(admob_iphone_sdk_20100818.tar.gz)を、
「SDK の説明書をPDF 文書でダウンロードしてください。」からPDF(AdMob_iPad_SDK_Instructions.pdf)を
ダウンロードします。

3. プロジェクトへの導入

ダウンロードしたSDKをプロジェクトに組み込みます。
PDFファイルに沿ってやればOKですが、英語なので一応流れを書いておきます。

Step1

SDK内の以下のファイルをAdMobフォルダごと、
プロジェクト直下にコピーします。

  • AdMob/
    • AdMobDelegateProtocol.h
    • AdMobView.h
    • libAdMob.a

Step2

「Frameworksを右クリック→追加→既存のフレームワーク」から、
以下を追加します。

  • AudioToolbox
  • CoreGraphics
  • MediaPlayer
  • MessageUI
  • QuartzCore

Step3

SDK内のTouchJSONフォルダをまるごとプロジェクト直下にコピーします。

Step4

publisher IDはSDK内に記載されているので問題なしです。

Step5(iPad)

実装です。次節で説明します。

4. 広告表示

やっとコーディングです。
お金がからむと前作業が長いですね^^

ここもPDF内のStep5に従うだけですが、量もそんなに多く無いので、
今回コードに加えた変更を全部載せておきます。

といっても、
「admob_iphone_sdk/sample_projects/AdMobSampleAdsiPad/Classes」内の
「EarthquakeListViewController.h, m」にPublisher ID含め全部書いてあるので、
コピーするだけなんですが。

AdMobDelegate

AdMobからのdelegateを受けるクラスを実装します。
今回はRootViewControllerにその機能を持たせています。

// RootViewController.h

#import "AdMobDelegateProtocol.h"
#import "AdMobView.h"

@interface RootViewController : UITableViewController <AdMobDelegate> {
// RootViewController.m

#pragma mark -
#pragma mark AdMobDelegate methods

- (NSString *)publisherIdForAd:(AdMobView *)adView {
    return @"publisher ID"; // this should be prefilled; if not, get it from www.admob.com
}

- (UIViewController *)currentViewControllerForAd:(AdMobView *)adView {
    // Return the top level view controller if possible. In this case, it is
    // the split view controller
    return self.splitViewController;
//    return self.navigationController.parentViewController;
}

- (void)willPresentFullScreenModalFromAd:(AdMobView *)adView {
    // IMPORTANT!!! IMPORTANT!!!
    // If we are about to get a full screen modal and we have a popover controller, dimiss it.
    // Otherwise, you may see the popover on top of the landing page.
    if (detailViewController.popoverController && detailViewController.popoverController.popoverVisible) {
        [detailViewController.popoverController dismissPopoverAnimated:YES];
    }
}

- (NSArray *)testDevices {
	return [NSArray arrayWithObjects: ADMOB_SIMULATOR_ID, nil];
}

プライベート指定解除

delegate内から使うDetailViewControllerのプロパティがプライペート化されちゃってるので、それを解除します。

// DetailViewController.h

@property (nonatomic, retain) UIPopoverController *popoverController;
// DetailViewController.m

@interface DetailViewController ()
//プライベートメソッドの解除(AdMobから使うので)
//@property (nonatomic, retain) UIPopoverController *popoverController;
- (void)configureView;
@end

AdMobViewの追加

最後に広告Viewを表示します。
今回はTableViewのFooterに表示するので、
RootViewControllerのinitWithPath内で行います。

        AdMobView *adMobView = [AdMobView requestAdOfSize:ADMOB_SIZE_320x270 withDelegate:self];
//        AdMobView *adMobView = [AdMobView requestAdOfSize:ADMOB_SIZE_320x48 withDelegate:self];
        self.tableView.tableFooterView = adMobView;

[完成]

広告とはいえ、画像が入ると見た目が良くなっていいですね。
AdMob導入

[まとめ]

AdMobは現状審査もないらしく、
非常に簡単な印象を受けました。

あとはどれくらいのお小遣いになるかですが、
もうちょっとでEdhitaをリリースしてみる予定なので、
そこで試してみようと思います。

それでは。

[コード]

今回のコードは「Edhita7.zip」に入っています。
GitHubのdownloadページからダウンロードして下さい。

Downloads for tnantoka's Edhita - GitHub

おまけと謝罪

今までgitのリポジトリにほとんどのファイルがコミットできていませんでした。
(git add .等をしていなかったので、新規ファイルが管理されていなかったのです。)

たまたま毎回ダウンロード用のファイルを用意していなので、少しは救われましたが、
試行錯誤の痕跡がなくなってしまってかなりショックです。

リポジトリをチェックアウトされた方々にもご迷惑をお掛けしました。

凹んでてもしょうがないので気を取り直して頑張ります。

IB不使用&オープンソースなiPadアプリ(テキストエディタ)を作る 第6回:AccessoryView、カーソル移動

第6回です。
奇跡的にまだ飽きてません。
この勢いで電子書籍を出せるまで頑張りたいと思います。

今回はキーボードの上部にAccessoryViewを表示させて、
そこから記号やタブを入力できるようにします。

また、ついでにツールバーのボタンからカーソルを左右に移動できるようにします。

参考

今回も参考書籍(第1回参照)とAppleのドキュメントのみです。

素材

引き続き、Soft * Accessory様の素材をお借りしています。

1. AccessoryViewの作成

まず、AccessoryViewを作成します。

と言っても、UIViewを継承したEdhitaAccessoryViewを作成し、
その上に記号入力用のUIButtonを配置するだけ。

特別なことは必要ありません。

// EdhitaAccessoryView.m

- (id)initWithTextView:(UITextView *)textView {
	if (self = [super init]) {
		
		textView_ = textView;

		NSInteger padding = 8;
		NSInteger margin = 8;
		NSInteger size = 46;
		
		self.frame = CGRectMake(0, 0, 768, size + padding * 2);
		self.backgroundColor = [UIColor lightGrayColor];
		
		// あんまりボタンを表示すると小さくせざるをえないので、使用頻度が高そうで入力しづらいやつを
		NSArray *titles = [NSArray arrayWithObjects: @"{", @"}" ,@"<", @">", @"[", @"]", @"+", @"*", @"=", @"_", @"#", @"|", @"\\", nil];		
		
		UIButton *button;
		
		// 記号
		NSInteger i = 0;
		for (NSString *title in titles) {

			button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
			button.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
			button.frame = CGRectMake((size + margin) * i + padding, padding, size, size);
			[button setTitle:title forState:UIControlStateNormal];
			[button addTarget:self action:@selector(insertDidPush:) forControlEvents:UIControlEventTouchUpInside];
			button.titleLabel.font = [UIFont systemFontOfSize: 20];
			[self addSubview:button];
			i++;
		}

		// タブ
		button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
		button.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
		button.frame = CGRectMake(self.frame.size.width - size - padding, padding, size, size);
		[button setTitle:@"\\t" forState:UIControlStateNormal];
		[button addTarget:self action:@selector(tabDidPush) forControlEvents:UIControlEventTouchUpInside];
		[self addSubview:button];

	}
	return self;
}

2. AccessoryViewの表示

先程作ったViewをTextViewのAccessoryViewとして設定します。

方法は、DetailViewControllerのinit内で、
textView_のinputAccessoryViewにインスタンスを代入するだけ。

これでAccessoryViewが表示されるようになります。
簡単ですね!

		if ([settings objectForKey:@"accessoryView"] == NULL || [settings boolForKey:@"accessoryView"]) {
			EdhitaAccessoryView *accessoryView = [[EdhitaAccessoryView alloc] initWithTextView:textView_];
			textView_.inputAccessoryView = accessoryView;
		}

人によってはAccessoryViewが邪魔だという人もいると思うので、
Settingsに項目を追加してON/OFFできるようにしています。
上のif文はONに設定されているか(デフォルトON)を判別しています。

		<dict>
			<key>Type</key>
			<string>PSGroupSpecifier</string>
			<key>Title</key>
			<string>Input</string>
		</dict>
		<dict>
			<key>Type</key>
			<string>PSToggleSwitchSpecifier</string>
			<key>Title</key>
			<string>Accessory View</string>
			<key>Key</key>
			<string>accessoryView</string>
			<key>DefaultValue</key>
			<true/>
		</dict>

3. 記号入力処理

AccessoryViewのボタンから記号を入力できるようにします。

やることは簡単で、ボタンがタップされたら、TextViewのselectedRangeを取得して、
ボタンのtitleLabel.text(タブの場合は\t)で置換します。
また、undoできるようにundoManagerに反対の処理(backspace)を仕込んでいます。
※ 見ての通り、view内に処理をがっつり書いちゃってます。
 MVC的にアウトだと思うんですが、
 この為に新たにControllerを作るのもどうかと思うし、
 これ以上DetailControllerを肥大化させてくないし…ということで一旦こういう実装にしています。
 今後勉強していく中で綺麗なアーキテクチャがわかったら直します。

// EdhitaAccessoryView.m

- (void)insertDidPush:(UIButton *)button {
	[self insertString:button.titleLabel.text];
}

- (void)tabDidPush {
	[self insertString:@"\t"];
}

- (void)insertString:(NSString *)string {

	NSMutableString *text = [textView_.text mutableCopy];

	NSRange range = textView_.selectedRange;
	[text replaceCharactersInRange:range withString:string];

	// カーソルが最後に行っちゃうので選択しなおす
	textView_.text = text;
	textView_.selectedRange = NSMakeRange(range.location + 1, range.length);

	// undo登録
	[[textView_ undoManager] registerUndoWithTarget:self selector:@selector(backSpace:) object:string];
}

- (void)backSpace:(NSString *)string {
	
	NSMutableString *text = [textView_.text mutableCopy];

	// 手前にカーソルを戻して空文字で1文字分置換
	NSRange range = textView_.selectedRange;
	textView_.selectedRange = NSMakeRange(range.location - 1, 1);
	[text replaceCharactersInRange:textView_.selectedRange withString:@""];
	textView_.text = text;
	
	textView_.selectedRange = NSMakeRange(range.location - 1, 0);

	// redo登録
	[[textView_ undoManager] registerUndoWithTarget:self selector:@selector(insertString:) object:string];
}

4. カーソル移動

最後にカーソルキーによるキャレットの移動です。

本当はAccessoryViewのボタンでやりたかったんですが、
どうしてもPortraitの時に幅が足りなくなるので、
ツールバーでやってます。

処理としては、selectedRangeのlocationを±1して設定しなおしているだけです。
上下移動は文字数とか考慮しなきゃいけないので保留です。

- (void)leftDidPush {
	NSRange range = textView_.selectedRange;
	textView_.selectedRange = NSMakeRange(range.location - 1, range.length);
	[[textView_ undoManager] registerUndoWithTarget:self selector:@selector(rightDidPush) object:nil];
}

- (void)rightDidPush {
	NSRange range = textView_.selectedRange;
	textView_.selectedRange = NSMakeRange(range.location + 1, range.length);
	[[textView_ undoManager] registerUndoWithTarget:self selector:@selector(leftDidPush) object:nil];
}

[完成]

できました!
AccessoryViewの実装

[まとめ]

いかがだったでしょうか。

だいぶTextEditorらしくなってきましたが、
肝心のSyntax Highlightingが後回しのまま…。

まだ検討もついてませんが、
そろそろやるしかないですねぇ。

[コード]

今回のコードは「Edhita6.zip」に入っています。
GitHubのdownloadページからダウンロードして下さい。

Downloads for tnantoka's Edhita - GitHub

Home

Page Top