Objective-C


【Objective-C】文字列内の改行を削除する

文字列内の改行を削除する方法

改行された
文字列

↓↓↓↓↓

改行された文字列

------------------------------------
//改行区切りで1行ずつ配列に入れる
NSMutableArray *lines = [NSMutableArray array];
[selectedWord enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
[lines addObject:line];
}];

//配列を連結
NSString *renketu_string = [lines componentsJoinedByString:@""];
NSLog(@"タイトルに表示する文字列:%@",renketu_string);
------------------------------------

参考ページ

【Xcode】TableViewでセルを選択したらセグエで画面遷移の設定

1.TableViewControllerから目的のViewへセグエでつなぐ

ストーリーボード上で行う。このとき注意すべきなのは、セグエをテーブルのセルから引っ張らないこと!TableViewController 上部の四角いボタンから目的のViewController へドラッグする。

2.セグエにIDを設定する

ストーリーボード上で新しいセグエを選択して、Attributes Inspector から ID を決める。「to○○ViewController」みたいな名前が分かりやすい。

3.実装ファイル(.m)に画面遷移の記述をする

------------------------------------------------------
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

[self performSegueWithIdentifier:@"セグエのID" sender:self];
}
------------------------------------------------------

参考ページ

【Xcode】TableViewのセルを二回タップしないと反応しない

TableViewのセルを一度タップしても反応しない。二度目以降は反応するという現象が起こった。

原因:

didSelectRowAtIndexPath を使用する場面で didDeselectRowAtIndexPath していた。

didDeselectRowAtIndexPath は、セルが解除されたタイミングで反応するイベント。

【Xcode】新しいViewController用の新しいクラスを作る

Object Library から 新しい View Controller をドラッグ&ドロップしたら、その View Controller に対する命令を記述するために、新しいクラスを作る必要がある。新しいクラスをつくると「新しいView Controller.h」と「新しいView Controller.m」のファイルが作成され、そこに命令文を記述していけばいい。

新しいクラスの作り方の手順。

1.ストーリーボードに View Controller を新規作成

ストーリーボードに View Controller オブジェクトをドラッグ&ドロップしてつくる。

2.新しいクラスを作る

「File」→「New」→「File...」でカスタムクラスを作る

3.新しいクラスと新しいViewControllerを関連付ける

ストーリーボードで新しくつくった View Controller を選択して、Identity Inspector の Cumtom Class から 先ほどつくったカスタムクラスを選択する。

【Xcode】TableViewセルの検索機能を実装する

1.TableView と Search Bar and Search Display を使うための下準備をする

1.プロジェクトからシングルビューをつくり、ストーリーボード上の ViewController に TableView と Search Bar and Search Display を配置する。

2.配置した2つの View(TableView と Search Bar and Search Display)を ViewController.mへそれぞれ接続する。

3.プロトコルを追加。

//ViewController.h(m)
----------------------------------------------
@interface ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>

//searchBar を接続(ストーリーボードからドラッグして行う)。
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;

//TableView を接続(ストーリーボードからドラッグして行う)。
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@end
----------------------------------------------

2.テーブルビューのセルにデータを表示させる

以下の記述をファイルに追加する。

//ViewController.h(m)
----------------------------------------------
@interface ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>

//searchBar を接続
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;

//TableView を接続
@property (weak, nonatomic) IBOutlet UITableView *tableView;

/**
* さきほど記述した場所の下に追記する。テーブルに表示する情報が入ります
*/
@property (nonatomic, strong) NSArray *dataSourceiPhone;
@property (nonatomic, strong) NSArray *dataSourceAndroid;

@end
----------------------------------------------
これを追記したタイミングで「"Assigning to 'id<~>' from incompatible type '~' "」のようなエラーが出る場合は、プロトコロルがきちんと実装できているか確認する。

//これも記述
----------------------------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

// デリゲートメソッドをこのクラスで実装する
self.tableView.delegate = self;
self.tableView.dataSource = self;

// テーブルに表示したいデータソースをセット
self.dataSourceiPhone = @[@"iPhone 4", @"iPhone 4S", @"iPhone 5", @"iPhone 5c", @"iPhone 5s"];
self.dataSourceAndroid = @[@"Nexus", @"Galaxy", @"Xperia"];

}
----------------------------------------------

//これもまるまる追記
----------------------------------------------
@implementation ViewController

(略)

//ここから下を全部追記

#pragma mark - TableViewDataSource delegate methods

/**
* テーブルに表示するデータ件数を返します(実装必須)
*
* @param tableView テーブルビュー
* @param section 対象セクション番号
*
* @return データ件数
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger dataCount;

switch (section) {
case 0:
dataCount = self.dataSourceiPhone.count;
break;
case 1:
dataCount = self.dataSourceAndroid.count;
break;
default:
break;
}
return dataCount;
}

/**
* テーブルに表示するセクション(区切り)の件数を返します(任意実装)
*
* @param テーブルビュー
*
* @return セクション件数
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}

/**
* テーブルに表示するセルを返します(実装必須)
*
* @param tableView テーブルビュー
* @param indexPath セクション番号・行番号の組み合わせ
*
* @return セル
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

// 再利用できるセルがあれば再利用する
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (!cell) {
// 再利用できない場合は新規で作成
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}

switch (indexPath.section) {
case 0:
cell.textLabel.text = self.dataSourceiPhone[indexPath.row];
break;
case 1:
cell.textLabel.text = self.dataSourceAndroid[indexPath.row];
break;
default:
break;
}

return cell;
}

@end
----------------------------------------------

セルにデータが表示てきていることを確認する。

3.検索バーをタップした時のTableViewControllerに検索結果を表示する準備をする

//検索結果を格納するNSArrayをプロパティで宣言する
----------------------------------------------
@interface ViewController ()

@property (nonatomic, strong) NSArray *dataSourceiPhone;
@property (nonatomic, strong) NSArray *dataSourceAndroid;

//ここを追記
//検索結果を格納する配列
@property (nonatomic, strong) NSArray *dataSourceSearchResultsiPhone;
@property (nonatomic, strong) NSArray *dataSourceSearchResultsAndroid;

@end
----------------------------------------------

結果を表示するViewControllerはStoryboardで 「Search Bar and Search Display」を紐づけした時に自動で参照が追加されて Self(UIViewController)にsearchDisplayController として紐づけられている。

//numberOfRowsInSectionを変更
----------------------------------------------
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger dataCount;

// ここのsearchDisplayControllerはStoryboardで紐付けされたsearchBarに自動で紐づけられている
//検索キーワードが入力されているか判定
if (tableView == self.searchDisplayController.searchResultsTableView) {
// 検索中のテーブルビューはこちらで処理
//セクションが複数ある場合はセクションごとに
switch (section) {
case 0:
dataCount = self.dataSourceSearchResultsiPhone.count;
break;
case 1:
dataCount = self.dataSourceSearchResultsAndroid.count;
break;
default:
break;
}
} else {
// 通常時のテーブルビューはこちらで処理
switch (section) {
case 0:
dataCount = self.dataSourceiPhone.count;
//もし、検索前のセルにデータを表示したくない場合はデータの数を0にする
//dataCount = 0;
break;
case 1:
dataCount = self.dataSourceAndroid.count;
break;
default:
break;
}
}
NSLog(@"%ld", (long)dataCount);
return dataCount;
}
----------------------------------------------

//cellForRowAtIndexPathを変更
----------------------------------------------
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
// 再利用できるセルがあれば再利用する
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (!cell) {
// 再利用できない場合は新規で作成
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}

// ここのsearchDisplayControllerはStoryboardで紐付けされたsearchBarに自動で紐づけられている
//検索キーワードが入力されているか判定
if (tableView == self.searchDisplayController.searchResultsTableView) {
// 検索中のテーブルビューはこちらで処理
//セクションが複数ある場合はセクションごとに
switch (indexPath.section) {
case 0:
cell.textLabel.text = self.dataSourceSearchResultsiPhone[indexPath.row];
break;
case 1:
cell.textLabel.text = self.dataSourceSearchResultsAndroid[indexPath.row];
break;
default:
break;
}
} else {
// 通常時のテーブルビューはこちらで処理
switch (indexPath.section) {
case 0: // iOS
cell.textLabel.text = self.dataSourceiPhone[indexPath.row];
break;
case 1: // Android
cell.textLabel.text = self.dataSourceAndroid[indexPath.row];
break;
default:
break;
}
}

return cell;
}
----------------------------------------------

4.データを絞り込む

----------------------------------------------
// 検索バーに入力された文字列を引数に、絞り込みをかけます
- (void)filterContainsWithSearchText:(NSString *)searchText
{
//CONTAINS右辺値が含まれているか,cは大文字小文字の区別なしオプション
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@", searchText];

self.dataSourceSearchResultsiPhone = [self.dataSourceiPhone filteredArrayUsingPredicate:predicate];
self.dataSourceSearchResultsAndroid = [self.dataSourceAndroid filteredArrayUsingPredicate:predicate];
}
----------------------------------------------

NSPredicate の詳細はこちら

//検索バーの文字を編集する度に呼ばれるデリゲートメソッド
----------------------------------------------
- (BOOL)searchDisplayController:controller shouldReloadTableForSearchString:(NSString *)searchString
{
// 検索バーに入力された文字列を引数に、絞り込みをかけます
[self filterContainsWithSearchText:searchString];

// YESを返すとテーブルビューがリロードされます。
// リロードすることでdataSourceSearchResultsiPhoneとdataSourceSearchResultsAndroidからテーブルビューを表示します
return YES;
}
----------------------------------------------

//セルが選択されたら
----------------------------------------------
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

NSLog(@"セルが選択されました");

}
----------------------------------------------
↑これで、1度目のタップでうまく反応しない場合は、didSelectRowAtIndexPath が didDeselectRowAtIndexPath になっていないか確認すること。

参考ページ

【Xcode】ナビゲーションバーのBackボタンのタイトルの変更

ナビゲーションバーのBackボタンのタイトルは、何も設定しないと自動的に前画面のタイトルが付けられる。自分で設定するには次のように記述する。

//画面遷移前のビューで設定する
------------------------------------------------

//ナビゲーションバーの back ボタンの指定
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"ボタンのタイトル" style:UIBarButtonItemStylePlain target:nil action:nil];

//タイトルの設定
[self.navigationItem setBackBarButtonItem:backBarButtonItem];

------------------------------------------------

【Xcode】TableViewでセルを選択してもハイライトにしない方法

Xcode でセルを選択してもハイライトにしない記述

//Objective-C での書き方
--------------------------------------------------
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell3" forIndexPath:indexPath];

//ここ
cell.selectionStyle = UITableViewCellSelectionStyleNone;

}
--------------------------------------------------

【Xcode】Supporting Files内のファイルをdocumentsディレクトリにコピーする

Supporting Files内のファイルをdocumentsディレクトリにコピーしたときのスクリプト。
初回起動時に実行したかったので、スクリプトは、AppDelegate.m 内の didFinishLaunchingWithOptions: に記述した。

--------------------------------------------------------------------
//didFinishLaunchingWithOptions は、アプリ起動時に呼び出される。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

//呼び出したいメソッドで下記を実行

NSError *error;

//NSFileManagerクラスは、Foundation フレームワーク(Cocoa Touchフレームワーク)にあるクラス。
//Objective-C で、パスの存在を調べたり、ディレクトリを作成したりするのに使う。

NSFileManager *fm = [NSFileManager defaultManager];

//documentsディレクトリのパス

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"コピーしたいファイル.jpg"];
NSLog(@"writableDBPath;%@",writableDBPath);


/*
//常に新しいDBファイルにしたい場合は、アプリ起動時に必ずファイルを消去する。
/* pathのファイルを削除 */
BOOL result = [fm removeItemAtPath:writableDBPath error:&error];
if (result) {
NSLog(@"ファイルを削除に成功:%@", writableDBPath);
} else {
NSLog(@"ファイルの削除に失敗:%@", error.description);
}
*/

BOOL result_flag = [fm fileExistsAtPath:writableDBPath];
if(!result_flag){

//dbが存在してなかったらここが呼ばれて、作成したDBをコピー

//Supporting Files内に置いたファイルのパス
//ここで null が帰ってきたりうまくコピーができなかったら、ファイルのコピーを許可していない可能性がある。許可の仕方はスクリプトのすぐ下に記述。

NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"コピーしたいファイル.jpg"];

//こっちの記述でもいい

//NSString *defaultDBPath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"db"];

//コピーを実行

BOOL copy_result_flag = [fm copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if(!copy_result_flag){

//失敗したらここ

NSLog(@"コピーに失敗");
}
}

return YES;
}
--------------------------------------------------------------------

コピーするファイルは、あらかじめ許可しておく必要があるので、うまくコピーできない場合は許可されているか確認する。

targets > BuildPhase > Copy Bundle Resources
から適宜該当ファイルを追加すれば解消される。参考

//FMDB使っていて、データファイルをコピーしたときのスクリプトがこれ↓ 参考
--------------------------------------------------------------------
NSError *error;
NSFileManager *fm = [NSFileManager defaultManager];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"test.db"];
NSLog(@"writableDBPath;%@",writableDBPath);

BOOL result_flag = [fm fileExistsAtPath:writableDBPath];
if(!result_flag){
//dbが存在してなかったらここが呼ばれて、作成したDBをコピー
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"test.db"];

BOOL copy_result_flag = [fm copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if(!copy_result_flag){
//失敗したらここ
NSLog(@"データベースのコピーに失敗");
}
}

//作成したテーブルからデータを取得
FMDatabase* db = [FMDatabase databaseWithPath:writableDBPath];
if ([db open]) {
[db setShouldCacheStatements:YES];

FMResultSet *rs = [db executeQuery:@"SELECT * FROM testdb"];
while ([rs next]) {
//ここでデータを展開
NSLog(@"データ展開%d %@", [rs intForColumn:@"id"], [rs stringForColumn:@"title"]);
}
[rs close];
[db close];
}else{
//DBが開けなかったらここ
}
--------------------------------------------------------------------

カスタムセルを使ったTableViewで画像とラベルと並べて表示

TableViewCellに画像とラベルを単純に並べて表示するだけなら、Object libraryからImage view と Label をドラッグ&ドロップするだけでいい。

(↑これをして「Need constraints for. Y position」のようなエラーが出たら、「制約」が設定されていないということなので、Auto Layout を解除するか、シーンの右下にある「Resolve Auto Layout Issues」から「add missing constraints」を実行するといい)

ただし、これだと画像とラベルの高さは同じになる。ラベルに複数行の渡る文字列を表示しようとすると、セルの高さが高くなって、画像の高さまで変わってしまう。

今回自分がやりたいことは、画像の高さはそのままで、ラベルのみ文字列の量に比例して高さを上げるという表示の仕方。

以下はその手順。

1.TableView を使うための下準備をする

1.ストーリーボードで、 Table View を ViewController にドラッグして、プロトコルの実装先である ViewController に dataSource と delegate を設定する。

2.プロトコルを実装する。

ViewController.m (h) 内に記述
------------------------------------------------

//プロトコルを実装
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>

@end

------------------------------------------------

3.セルの表示以外のプログラムをいろいろ記述する

2.テーブルビューにテーブルビューセルを追加し、ID を設定する

1.ストーリーボードで、テーブルビューに UITableViewCell をドラッグ&ドロップする。

2.追加したセルにセルIDを「myCell」と設定する。

3.追加したセルの中にImage View と Label を追加する

1.Object Library 内になる Image View と Label をセルの中に並べて配置する。各オブジェクトのサイズ調整も行う。

2.それぞれの tag に、「1」「2」と設定する。

3.Label の numberOfLines を「0」にして、複数行表示を有効にする。

4.プログラムを作る

ViewController.m 内に記述
------------------------------------------------
//セクション数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}

//行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}

//表示するセル
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

//セルIDを myCell と設定したセルを使う
NSString *cellIdentifier = @"myCell";

//カスタムセルを準備する
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}

//tag番号1のImagaViewに画像を設定する
UIImageView *imgView = (UIImageView *)[cell viewWithTag:1];
//Supporting Files に sample.jpg という画像データを入れておく
UIImage *img = [UIImage imageNamed:@"sample.jpg"];
imgView.image = img;

//tag番号2のラベルに文字を設定する
UILabel *label2 = (UILabel *)[cell viewWithTag:2];
label2.text = [NSString stringWithFormat:@"%ld行目", (long)indexPath.row];

//表示する文字列にフィットするようにラベルを伸縮させる
[label2 sizeToFit];

return cell;

}
------------------------------------------------

sizeTOFit を有効にするために、セルの AutoLayout をオフにすること!

5.各行の高さを個別に計算して決める

------------------------------------------------
//各行の高さを決めるメソッド
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

//表示したい文字列。この文字列が表示できるだけ、セルの高さを確保する
NSString * text = [NSString stringWithFormat:@"%ld行目", (long)indexPath.row];

//表示最大幅と高さ
CGSize maxSize = CGSizeMake(200, CGFLOAT_MAX);

//表示するフォントのサイズ
NSDictionary *attr = @{NSFontAttributeName: [UIFont boldSystemFontOfSize:17.0]};

//以上を踏まえた上で、表示に必要なサイズ
CGSize modifiedSize = [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil].size;

//上下10pxずつの余白を加えたものと70pxのうち、大きい方を返す
return MAX(modifiedSize.height + 20, 70);
}
------------------------------------------------

UITableViewAutomaticDimension を使えばもっと簡単にセルの高さは決められるらしい。

以上。

実行して動作を確認。セルの高さが伸縮しない場合は、AutoLayout がオフになっているか確認する。sizeTOFit は、AutoLayout が有効だと機能しないよう。

参考:こちらおよび、iPhoneアプリ開発の教科書 P.364~

【Xcode】TableViewで画像とテキストを並べる

Xcode の TableView で画像とテキストを並べる表示をする Objective-C のスクリプト例
-----------------------------------------------------------------------------
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

//テキスト
cell.textLabel.text = myArray[indexPath.row];

//画像
cell.imageView.image = [UIImage imageNamed:@"画像.gif"];

return cell;
}
-----------------------------------------------------------------------------

参考ページ

1 / 212