私はiOSが初めてです。カメラからキャプチャした画像をCoreData
に保存するアプリケーションを作成しようとしています。 NSString
s、NSDate
などのデータを保存する方法を知っていますが、画像の保存に苦労しています。ディスクに書き込み、ファイルに書き込む必要があるという記事をたくさん読んでいますが、理解できないようです。
次のコードは、他のデータをコアデータに保存するために使用するコードです。
- (IBAction)submitReportButton:(id)sender
{
UrbanRangerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"PotholesDB" inManagedObjectContext:appDelegate.managedObjectContext];
NSManagedObject *newPothole = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext];
[newPothole setValue:self.relevantBody.text forKey:@"relevantBody"];
[newPothole setValue:self.subjectReport.text forKey:@"subjectReport"];
[newPothole setValue:self.detailReport.text forKey:@"detailReport"];
// [newPothole setValue:self.imageView forKey:@"photo"];
NSDate *now = [NSDate date];
//NSLog(@"now : %@", now);
NSString *strDate = [[NSString alloc] initWithFormat:@"%@", now];
NSArray *arr = [strDate componentsSeparatedByString:@" "];
NSString *str;
str = [arr objectAtIndex:0];
NSLog(@"now : %@", str);
[newPothole setValue:now forKey:@"photoDate"];
[newPothole setValue:self.latitudeLabel.text forKey:@"latitude"];
[newPothole setValue:self.longitudeLabel.text forKey:@"longitude"];
[newPothole setValue:self.addressLabel.text forKey:@"streetName"];
[newPothole setValue:streeNameLocation forKey:@"location"];
NSError *error;
[managedObjectContext save:&error];
UIAlertView *ll = [[UIAlertView alloc] initWithTitle:@"Saving" message:@"Saved data" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[ll show];
}
Binary Data属性タイプを使用して、Core Dataに画像を保存できます。ただし、いくつかの点に注意する必要があります。
UIImageを常にpngやjpgなどのポータブルデータ形式に変換します。例:
NSData *imageData = UIImagePNGRepresentation(image);
この属性で「外部ストレージを許可する」を有効にします Core Dataは、特定のしきい値に達するとデータを外部ファイルに移動します。このファイルもCore Dataによって完全に管理されているため、心配する必要はありません。
パフォーマンスの問題が発生した場合は、バイナリデータ属性を別のエンティティに移動してみてください。
NSManagedObjectサブクラスのインターフェースの背後でNSDataへの変換を抽象化する必要があります。そのため、UIImageからNSDataへの変換、またはその逆について心配する必要はありません。
画像がモデルのエンティティに強く関連していない場合、Core Dataの外部に保存することをお勧めします。
XcdatamodelIdサブクラスでは、画像エンティティをNSData
...として宣言します。画像データはバイナリ形式であるため、UIImage
形式は使用できません。
@property (nonatomic, retain) NSData *imag;
実装ファイルで.UIImage
をNSData
に変換します
UIImage *sampleimage = [UIImage imageNamed:@"sampleImage.jpg"];
NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);
そして最後に保存します
[obj setValue:dataImage forKey:@"imageEntity"]; // obj refers to NSManagedObject
- (void)imageChanged:(UIImage*)image{
if (self.detailItem) {
[self.detailItem setValue:UIImagePNGRepresentation(image) forKey:kSignatureImage];
}
}
これは非常に簡単な例です。 self
はコアデータを使用するView Controllerであり、self.detailItemは通常のNSManagedObjectです。そのプロジェクトでは、エンティティのモデルクラスを作成しませんでしたが、属性にアクセスするにはKVCパターンを厳密に使用しました。ご想像のとおり、属性の名前は"signatureImage"
で、#define constant kSignatureImage
で定義しました。
これは、イメージがコアデータから復元される場所です。
self.signatureCanvas.image = [UIImage imageWithData:[self.detailItem valueForKey:kSignatureImage]];
繰り返しますが、self
はView Controller、signatureCanvas
はUIImageView
サブクラス、.image
はimage
から継承された通常のUIImageView
プロパティです。 detailItem
、これも通常のNSManagedObject
です。
この例は、現在取り組んでいるプロジェクトから取ったものです。
コアデータに画像のような大きなデータオブジェクトを保存したり、それらをファイルに分けたりすることには長所と短所があります。それらをファイルに保存するということは、関連するデータオブジェクトが削除されたときにそれらを削除する責任があるということです。これにより、コーディングのオーバーヘッドが発生し、プログラミングエラーが発生する場合があります。一方、基になるデータベースの速度が低下する可能性があります。パフォーマンスに関して共有できるこのアプローチの経験はまだ十分ではありません。最終的に、占有されるディスクストレージは合計でほぼ同じサイズになります。
Swift 5およびSwift 4.2の場合
UIImage
をData
に変換:
let imageData = image.jpegData(compressionQuality: 1.0)
CoreData
に保存:
let object = MyEntity(context: managedContext) //create object of type MyEntity
object.image = imageData //add image to object
do {
try managedContext.save() //save object to CoreData
} catch let error as NSError {
print("\(error), \(error.userInfo)")
}
UIImageとしてCore Dataに画像を保存することが可能です。データベースはファイルを保存するためのものではないため、これは良い習慣とは見なされませんが。コアデータを使用して画像を直接保存するのではなく、携帯電話の画像データが保存されている場所へのファイルパスを使用します。
とにかく、サイドプロジェクトの開発中に見つけた最良の方法を以下に示します
画像タイプにする属性を選択し、タイプとして transformable を選択します
エディターに移動し、 NSManagedObjectサブクラスの作成 を選択します
プロセスは、エンティティの数に応じて2つのSwiftファイルを作成します(エンティティは1つしかありませんでした)。ここで、<EntityName> + CoreDataProperties.Swift
ファイルを選択し、 IKitのインポート
@NSManaged public var UIImage definition
で 定義へのジャンプ をクリックすると、作業が完了します。
エンティティに対してアクションを実行し、<EntityName>?.value(forKey: "<attributeName>") as? UIImage
をダウンキャストすることで、イメージ属性を取得、保存、編集できます。
エンティティをNSManagedObject
タイプとして使用する必要があり、何らかの理由で、作成されたサブクラスから直接イメージにアクセスできませんでした。
この問題を解決するのに役立つリンクはほとんどありません
IOSには他の永続ストレージが利用できるのに、なぜコアデータに画像を保存したいのかわかりません。キャッシュ目的で画像を保存するだけの場合は、ドキュメントディレクトリまたはキャッシュディレクトリに保存できます。ハッピーコーディング...
以下のURL、ドキュメントディレクトリで画像を保存および取得する方法を参照してください。
http://www.wmdeveloper.com/2010/09/save-and-load-uiimage-in-documents.html