iOS-Slides-11+sqlite-coredata - Tapbits

bawltherapistΛογισμικό & κατασκευή λογ/κού

13 Δεκ 2013 (πριν από 3 χρόνια και 4 μήνες)

150 εμφανίσεις

Петко Пенчев, TapBits.com
Разработване на
приложения
за iOS
Thursday, June 23, 2011
SQLite

Бърз, надежден и много ефективен по
отношение на памет

Използва един файл за съхранение на данните

Open Source, но е съвместим с iOS

За съжаление не е подходящ за всичко
(интензивни операции свързани с запис и т.н.)

Не е сървър базирано решение (недостатъци
свързани с concurrency и т.н.), но е компактен и
много ефективен за приложения под iOS
Thursday, June 23, 2011
SQLite и iOS

C API

int sqlite3_open(constchar*filename,sqlite3**db); //get a database into db

int sqlite3_exec(sqlite3 *db,
// execute SQL statements
const char *sql,
int (*callback)(void *, int, char **, char **),
void *context,
char **error);

int mycallback(void* context,int count,char** values,char** cols);
//data returned

int sqlite3_close(sqlite3 *db); // close database
Thursday, June 23, 2011
SQLite и iOS

Как да си създадем база данни
Terminal sqlite3 test.sqlite3
CREATE TABLE todo(pk INTEGER PRIMARY KEY, text VARCHAR(25), priority INTEGER,
complete BOOLEAN);
INSERT INTO todo(text,priority,complete) VALUES('Take out the trash',3,0);
INSERT INTO todo(text,priority,complete) VALUES('Do Computer Science homework',
1,0);
INSERT INTO todo(text,priority,complete) VALUES('Learn Objective C',1,0);
INSERT INTO todo(text,priority,complete) VALUES('DIGG this tutorial',2,0);
.quit
Thursday, June 23, 2011
SQLite и iOS

Създаваме проект в XCode,
Navigation Based App

Добавяме .sqlite файла, който сме създали
към проекта
Thursday, June 23, 2011
SQLite и iOS

Добавяме sqlite поддръжка в проекта
Frameworks, Аdd - Existing Frameworks - libsqlite3.0.dylib

Добавяме SQLite header и прилагаме в
интерфейса на клас
import UIKit/UIKit.h
import "/usr/include/sqlite3.h"
interface databaseViewController : UIViewController {

sqlite3 *contactDB;
}
- (IBAction) saveData;
- (IBAction) findContact;
end
Thursday, June 23, 2011
SQLite и iOS
...
NSString *docsDir;
NSArray *dirPaths;
dirPaths  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir  [dirPaths objectAtIndex:0];
databasePath  [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: "test.sqlite3"]];
NSFileManager *filemgr  [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ]  NO)
{

const char *dbpath  [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB)  SQLITE_OK)
{
char *errMsg;
const char *sql_stmt  "CREATE TABLE IF NOT EXISTS CONTACTS (...)";
if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) ! SQLITE_OK)
{
// Failed to create table
}
sqlite3_close(contactDB);
} else {
// Failed to open/create database
}
}
[filemgr release];
...
Thursday, June 23, 2011
SQLite и iOS
- (void) saveData
{
sqlite3_stmt *statement;
const char *dbpath  [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB)  SQLITE_OK)
{
NSString *insertSQL  [NSString
stringWithFormat:
"INSERT INTO CONTACTS (name, address, phone) VALUES ("%", "%", "%")",
name.text, address.text, phone.text];
const char *insert_stmt  [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement)  SQLITE_DONE)
// Contact added
else
// Failed
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
Thursday, June 23, 2011
SQLite и iOS
- (void) findContact
{
const char *dbpath  [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &contactDB)  SQLITE_OK)
{
NSString *querySQL  [NSString
stringWithFormat: "SELECT address, phone FROM contacts WHERE name"%"", name.text];
const char *query_stmt  [querySQL UTF8String];

if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL)  SQLITE_OK)
{
if (sqlite3_step(statement)  SQLITE_ROW)
{
NSString *addressField  [[NSString alloc]
initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
address.text  addressField;
NSString *phoneField  [[NSString alloc]
initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
phone.text  phoneField; status.text  "Match found";
[addressField release]; [phoneField release];
} else {
status.text  "Match not found"; address.text  ""; phone.text  "";
}
sqlite3_finalize(statement);
}
sqlite3_close(contactDB);
}
}
Thursday, June 23, 2011
SQLCipher

Базиран на SQLite

SQLite Няма вградена поддръжка за encryption
на записите

SQLite е надграждане на имплементацията на
SQLite layer-а в iOS

Разширение на C API, което ни позволява
- on-the-fly encryption, decryption
- AES 256
http://sqlcipher.net/documentation/ios
Thursday, June 23, 2011
SQLite vs. Core Data

SQLite
- OpenSource широка поддръжка
- Междуплатформена съвместимост
- Objective C wrappers (FMDB)
- RDBS / SQL синтаксис, който за много от нас удобен
- C API може би най-големият недостатък

Core Data
- Обектно ориентиран framework
- Високо ниво на абстрация между данни и обекти
- Native метод вграден в iOS
- “Визуално програмиране” и връзка между данни и
обекти
- Използва собствен binary формат или SQLite
Thursday, June 23, 2011
Core Data
Managed Object Model
Може да се приеме като DB schema. Това е клас
който съдържа дефиниции за всеки обект (Entities),
които се съхраняват в база данни.Типично,
използвайки визуален редактор създаваме обектите,
техните атрибути и взаимовръзки.
Persistent Store Coordinator
Може да се приеме като връзка към база данни, установява фактическото
име и разположение на базата данни, която ще съхранява обектите.
Използва се от managed context обекта при нужда да съхрани данни.
Managed Object Context
Може да се приеме като временна площадка за обектите, чийто източник
е базата данни. Много често използван термин, практически винаги когато
имаме нужда да вземем, вмъкнем, изтрием или променим обект използваме
метод на managed object context.
Thursday, June 23, 2011
Създаване на модела

Създаваме нов Navigation Based проект в
XCode
Core Data
Thursday, June 23, 2011
Създаване на модела
Text

Използване на файла с “модела” (данните)
Thursday, June 23, 2011
Създаване на модела

Entity (запис, статия) е аналогията на Table в DB
и Object в кода
- Entity не съдържа код
- Entity съдържа само
описание на данните
Thursday, June 23, 2011
Създаване на модела

Attribute намира своята аналогия в кода
на property/instance variable или Column
в DB

Attribute съдържа конкретна стойност от
фиксиран тип (string, number, date и т.н.)
Thursday, June 23, 2011
Създаване на модела

Attribute намира своята аналогия в
property/instance variable

Attribute съдържа конкретна стойност от
фиксиран тип (string, number, date и т.н.)
Thursday, June 23, 2011
Създаване на модела

Attribute и характеристики според типа
Thursday, June 23, 2011
Създаване на модела

Добавяне на още едно Entity
Author с Attributes name и email от тип String
Thursday, June 23, 2011
Създаване на модела

Добавяне на още едно Entity
Topic с Attributes title от тип String
Thursday, June 23, 2011
Създаване на модела

Връзки (relationship) между Entities

Нов тип Property наречено Relationship
Relationship
-а е винаги между
Entity
-та, не между Attributes
Thursday, June 23, 2011
Създаване на модела

Ще създадем още един Relationship
между Author и Post
Thursday, June 23, 2011
Създаване на модела

Inverse Relationship
- препоръчва се, практически за всички случай
- за по-добра data integrity
Thursday, June 23, 2011
Създаване на модела

Добавяме още един Inverse Relationship
между Post и Topic
Thursday, June 23, 2011
Създаване на клас за Entry
Thursday, June 23, 2011
Създаване на клас за Entry
Thursday, June 23, 2011
Entry Class Post
import CoreData/CoreData.h
class
Author
;
class
Topic
;
interface
Post
:
NSManagedObject

{
}
property (nonatomic, retain) NSDate * creationDate;
property (nonatomic, retain) NSString * body;
property (nonatomic, retain) NSString * title;
property (nonatomic, retain)
Author
* author;
property (nonatomic, retain)
Topic
* topic;
end
import "Post.h"
import "Author.h"
import "Topic.h"
implementation Post

dynamic
creationDate;

dynamic
body;

dynamic
title;

dynamic
author;

dynamic
topic;
end
Thursday, June 23, 2011
Entry Class Author
import CoreData/CoreData.h
class Post;
interface Topic : NSManagedObject
{
}
property (nonatomic, retain) NSString * title;
property (nonatomic, retain) NSSet* posts;
end
interface Topic (CoreDataGeneratedAccessors)
- (void)addPostsObject:(Post *)value;
- (void)removePostsObject:(Post *)value;
- (void)addPosts:(NSSet *)value;
- (void)removePosts:(NSSet *)value;
end
import "Topic.h"
import "Post.h"
implementation Topic
dynamic title;
dynamic posts;
end
Thursday, June 23, 2011
Entry Class Topic
import CoreData/CoreData.h
class Post;
interface Topic : NSManagedObject
{
}
property (nonatomic, retain) NSString * title;
property (nonatomic, retain) NSSet* posts;
end
interface Topic (CoreDataGeneratedAccessors)
- (void)addPostsObject:(Post *)value;
- (void)removePostsObject:(Post *)value;
- (void)addPosts:(NSSet *)value;
- (void)removePosts:(NSSet *)value;
end
import "Topic.h"
import "Post.h"
implementation Topic
dynamic title;
dynamic posts;
end
Thursday, June 23, 2011
Установяване
NS
ManagedObjectContext
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext {

if (managedObjectContext_ ! nil) {
return managedObjectContext_;
}

NSPersistentStoreCoordinator *coordinator  [self persistentStoreCoordinator];
if (coordinator ! nil) {
managedObjectContext_  [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
Thursday, June 23, 2011
Установяване
NS
ManagedObjectModel
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {

if (managedObjectModel_ ! nil) {
return managedObjectModel_;
}
NSString *modelPath  [[NSBundle mainBundle] pathForResource:"coredata_app" ofType:"momd"];
NSURL *modelURL  [NSURL fileURLWithPath:modelPath];
managedObjectModel_  [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
Thursday, June 23, 2011
Установяване
NS
PersistentStoreCoordinator
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator_ ! nil) {
return persistentStoreCoordinator_;
}

NSURL *storeURL  [[self applicationDocumentsDirectory]
URLByAppendingPathComponent:"coredata_app.sqlite"];

NSError *error  nil;
persistentStoreCoordinator_  [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self
managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeURL options:nil error:&error]) {

NSLog("Unresolved error %, %", error, [error userInfo]);
abort();
}

return persistentStoreCoordinator_;
}
Thursday, June 23, 2011
Core Data ‘Insert’
NSManagedObjectContext *context  [self managedObjectContext];
Post *post  [NSEntityDescription insertNewObjectForEntityForName:"Post"
inManagedObjectContext:context];
post.title  "Post title 1";
post.body  "Post body 1";
post.creationDate [NSDate date];

Author *author  [NSEntityDescription insertNewObjectForEntityForName:"Author"
inManagedObjectContext:context];
author.name  "Ivan Stoyanov";
author.email  "ivanstoyanov.com";

Topic *topic  [NSEntityDescription insertNewObjectForEntityForName:"Topic"
inManagedObjectContext:context];
topic.title  "Topic title 1";

post.author  author;
post.topic  topic;

NSError *error;
if (![context save:&error]) {
NSLog("Whoops, couldn't save: %", [error localizedDescription]);
}
Thursday, June 23, 2011
Core Data ‘Select’
...
NSFetchRequest *fetchRequest  [[NSFetchRequest alloc] init];
NSEntityDescription *entity  [NSEntityDescription entityForName:"Post"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSArray *fetchedObjects  [context executeFetchRequest:fetchRequest error:&error];
for (
Post
*info in fetchedObjects) {
NSLog("Post.Title: %", info.title);
NSLog("Post.Body: %", info.body);

Topic
*topicdetails  info.topic;
NSLog("Topic.Title: %", topicdetails.title);


Author
*authordetails  info.author;
NSLog("Author.Name: %", authordetails.name);
NSLog("Author.Email: %", authordetails.email);
}
[fetchRequest release];
...
2011-02-03 11:14:07.519 coredata-app[23113:207] Post.Title: Post title 1
2011-02-03 11:14:08.776 coredata-app[23113:207] Post.Body: Post body 1
2011-02-03 11:14:10.734 coredata-app[23113:207] Topic.Title: Topic title 1
2011-02-03 11:14:12.273 coredata-app[23113:207] Author.Name: Ivan Stoyanov
2011-02-03 11:14:12.953 coredata-app[23113:207] Author.Email: ivanstoyanov.com
Thursday, June 23, 2011
Core Data - NSFetchRequest

NSFetchRequest няколко важни неща
-
NSEntityDescription
от кое Entity да извличаме обекти
-
NSPredicate
указва кои Entities да бъдат извличани
-
NSSortDescriptor
s указва реда на върнатите обекти в
масива
- колко обекта да бъдат извличани
Thursday, June 23, 2011
NSFetchRequest
NSFetchRequest *request  [[NSFetchRequest alloc] init];
NSEntityDescription *entity  [NSEntityDescription entityForName:"Post"
inManagedObjectContext:context];
request.fetchBatchSize  20;
request.fetchLimit  100;
request.sortDescriptors  [NSArray arrayWithObject:sortDescriptor];
NSString *titleterm  “Objective C”;
request.predicate  [NSPredicate predicateWithFormat:“title contains %”, titleterm];
[request setEntity:entity];
Thursday, June 23, 2011
NSPredicate

Формат на predicate
“uniqueId  %”, [flickrInfo objectForKey:“id”]
“% in tags”, (NSManagedObject *)
// tags is a to-many relationship
“viewed  %”, (NSDate *)
// viewed is a Date attribute in the data mapping
“name contains[c] %”, (NSString *) // matches the string in name attribute case insensitively
NSPredicate *pred1  [NSPredicate predicateWithFormat:"age  21"];
NSPredicate *pred2  [NSPredicate predicateWithFormat:
"name  % OR name  %", "Mary", "Joe"];
...
NSPredicate *pred  [NSPredicate predicateWithFormat:
"name LIKE[cd] %", "Bob"];
Thursday, June 23, 2011
NSCompondPredicate
NSArray *preds  [NSArray arrayWithObjects: pred1,pred2, nil];
NSPredicate *notPred  [NSCompoundPredicate
notPredicateWithSubpredicates:preds
];
NSPredicate *andPred  [NSCompoundPredicate
andPredicateWithSubpredicates:preds
];
NSPredicate *orPred  [NSCompoundPredicate
orPredicateWithSubpredicates:preds
];
Thursday, June 23, 2011
Изтриване на ‘запис’
NSManagedObjectContext *context  [self.fetchedResultsController managedObjectContext];

[context deleteObject:
(NSManagedObject *)anObject
];

// Save the context.
NSError *error  nil;
if (![context save:&error]) {
...
}
Thursday, June 23, 2011
Други

Optimistic locking
deleteConflictsForObject:

Roll-back на незаписаните промени

Undo/Redo

Stateness (след колко време след изтегляне даден обект да
се изтегля отново)

Наблюдател за промени (NSFetchedResultsController)
Thursday, June 23, 2011
NSFetchedResultsController

Подходящ за UITableView dataSource
synthesize fetchedResultsControllerfetchedResultsController_
- (NSFetchedResultsController *)fetchedResultsController {

if (fetchedResultsController_ ! nil) {
return fetchedResultsController_;
}

NSFetchRequest *fetchRequest  [[NSFetchRequest alloc] init];
NSEntityDescription *entity  [NSEntityDescription entityForName:"Post" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor  [[NSSortDescriptor alloc] initWithKey:"title" ascending:NO];
NSArray *sortDescriptors  [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController  [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:"Root"];
aFetchedResultsController.delegate  self;
self.fetchedResultsController  aFetchedResultsController;

[aFetchedResultsController release]; [fetchRequest release]; [sortDescriptor release]; [sortDescriptors release];

NSError *error  nil;
if (![fetchedResultsController_ performFetch:&error]) {
NSLog("Unresolved error %, %", error, [error userInfo]);
abort();
}

return fetchedResultsController_;
}
Thursday, June 23, 2011
NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id NSFetchedResultsSectionInfo)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
Thursday, June 23, 2011
NSFetchedResultsControllerDelegate
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {

UITableView *tableView  self.tableView;

switch(type) {

case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;

case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
Thursday, June 23, 2011
NSFetchedResultsController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id NSFetchedResultsSectionInfo sectionInfo  [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {

NSManagedObject *managedObject  [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text  [[managedObject valueForKey:"timeStamp"] description];
}
Thursday, June 23, 2011
Core Data

http://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/
iPhoneCoreData01/Introduction/Introduction.html

http://www.raywenderlich.com/934/core-data-tutorial-getting-started

http://www.techotopia.com/index.php/An_iPhone_OS_Core_Data_Tutorial

http://www.raywenderlich.com/980/core-data-tutorial-how-to-preloadimport-existing-data
Thursday, June 23, 2011