Creating Repository pattern for use with local .SQLite db in Swift - repository-pattern

I am building a SwiftUI app that pulls information from a local .SQLite database (using the SQLite.swift wrapper from https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md). I need to build a repository that sits between the View Service and the Database Manager. I am very new to repository pattern, and am struggling to find 1) documentation for using repository pattern in Swift 5, and 2) what exactly needs to be in the repository.
I found this example for using repository pattern in Swift, but it uses a web-based API for its code examples, and I can't find anything for use with a local db.
Code below is what I have in the repository so far:
struct doMaster: Codable {
let doID: Int64
let doName: String
let doState: Bool
let doCompletedState: Bool
let doCategory: String
}
struct doDescription: Codable {
let doID: Int64
let doDescription: String
}
struct doStreaks: Codable {
let doID: Int64
let doStreak: Int64
}
struct doCategories: Codable {
let category: String
let categoryColor: String
}
class LocalRepository {
let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? ""
let task =
}
Any help would be very much appreciated. Thank you in advance!

Related

What models and fields do I need to handle subscriptions such as Apple's Autorenewable Subscriptions?

I want to build an autorenewable subscription service, with an introductory trial period. There doesn't seem to be much written documentation on what models and fields I need to best model (and futureproof) my subscriptions. I'm starting with Apple's App store right now, but I do have a web interface and want to go to the Play Store at some point.
From this video: https://developer.apple.com/videos/play/wwdc2018/705/ it seems like the minimum I need is something like a Subscription model with fields userId, productId, originalTransactionId, latestExpiresDate, consumedProductDiscounts, latestReceiptData.
Is there anything else I need?
Will I be able to properly retrieve other subscription information in the future and augment my table (i.e. the billingRetry information as suggested in the video for grace periods; my understanding is by sending the saved receipt data I can get the JSON blob again and retrieve additional fields if I need to)?
Is this extensible to co-exist with web and Play Store subscriptions?
These is the models we use to handle the subscription. maybe it helps you.
struct BillingTransaction : Codable {
var expires_date: String
var original_purchase_date: String
var is_in_intro_offer_period: Bool
var product_id: String
var original_transaction_id: Int
var transaction_id: Int
}
struct BillingReceipt : Codable {
var app_item_id: String
var application_version: String
var bundle_id: String
var in_app: [BillingTransaction]
}
struct BillingRenewalInfo : Codable {
var product_id: String
var auto_renew_product_id: String
var auto_renew_status: Int
var is_in_billing_retry_period: Int
var original_transaction_id: Int
}

FMDB & Swift, " Optional("no such table: Student info") " in real device but it can be done in simulator

I'm newbie, plz help me to solve this out, I still have lots of other things to work on, really thank you thank you very much!
This is a further question after How to use FMDB on the generic iOS device instead of simulator?
When I execute the app on my device and the error threw out: "no such table: Student info", I've print all the path and they all pointed to the same file so I assumed the database has already copied? Console shows like this:
file:///var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/
file:///var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/Data.db
/var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/Data.db
file:///var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/
file:///var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/Data.db
/var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/Data.db
/var/mobile/Containers/Data/Application/B5E42F3C-524E-4BBF-8667-1EED0C963A77/Documents/Data.db
<NSFileManager: 0x17401c1b0>
2017-03-13 16:43:25.446039 Test1.3[16360:5045427] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-03-13 16:43:25.457278 Test1.3[16360:5045427] [MC] Reading from public effective user settings.
Insert failed:
Optional("no such table: Student info")
The Data.db is in my bundle resources in target; and the contents in my device is a blank Data.db;
The 2nd question: If you look at the Utility.Swift in the previous question, although the app works good on simulator but after it was loaded, there should be an alertView said "Your database copy successfully", but it didn't. Following is that part of the code:
class func copyFile(_ fileName: NSString){
let dbPath: String = getPath(fileName as String)
let fileManager = FileManager.default
print(dbPath)
print(fileManager)
if !fileManager.fileExists(atPath: dbPath) {
let documentsURL = Bundle.main.resourceURL
let fromPath = documentsURL!.appendingPathComponent(fileName as String)
var error : NSError?
do {
try fileManager.copyItem(atPath: fromPath.path, toPath: dbPath)
}
catch let error1 as NSError {
error = error1
}
if(error != nil){
self.invokeAlertMethod("Error Occured", strBody: "\(error?.localizedDescription)" as NSString, delegate: nil)
}
else{
self.invokeAlertMethod("Successed", strBody: "Your database copy successfully", delegate: nil)
}
}
}
Okay for answering this question I went through your demo.
Where I found couple of mistakes. Let me go through one by one.
1) Your class Utility have a getPath method. What it does it will
keep copying db every time although db is already present in documents
directory and your documents directory db will be replaced with the sample structure. You should always check that if db is already present in documents directory or not.
2) Your db was getting copied into documents directory but structure
wasn't. There was no Student info table in db of documents directory.
3) Please avoid using space or any special characters in table names.
So what I did just corrected your method getPath in utility class.
Please replace your method with this one
class func getPath(_ fileName: String) -> String {
let bundlePath = Bundle.main.path(forResource: "Data", ofType: ".db")
let destPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileManager = FileManager.default
let fullDestPath = URL(fileURLWithPath: destPath).appendingPathComponent("Data.db")
if fileManager.fileExists(atPath: fullDestPath.path){
print("Database file is exist")
print(fileManager.fileExists(atPath: bundlePath!))
}else{
do{
try fileManager.copyItem(atPath: bundlePath!, toPath: fullDestPath.path)
}catch{
print("\n",error)
}
}
print(fullDestPath.path)
return fullDestPath.path
}
After changing this piece of code I tried to run in my device and inserted couple of records.
Let me know if you have any more questions.
If you find this answer helpful just accept it.
First trying delete your app and then reinstall it.
OR
I have created a project over FMDB in Swift which you can use to solve your issue. FMDB Wrapper class you can use in Objective C project as well.
https://github.com/LalitKY/Swift-FMDB
Hope this helps.

Alamofire.request does not map with custom object

I was trying to create a sample app in swift that maps with alamofire with alamofire object mapper. The whole idea of this sample app is to map json response with custom model that I make. But when I try to loop the object list, it says that custom object is not compatible and its a dictionary.
Here is my network layer code
// MARK: retrieve country list
func retrieveCountryList(completion: #escaping (_ result: NSArray) -> Void) {
Alamofire.request("https://restcountries.eu/rest/v2/all").
responseJSON{(response: DataResponse<Any>) in
let result = response.result.value;
let resultsArray = result as! NSArray
completion(resultsArray)
}
}
and model
class Country : Mappable {
var name:String?
var capital:String?
required init(map : Map) {
}
func mapping(map: Map) {
name <- map["name"]
capital <- map["capital"]
}
}
It seems that the response is doesn't directly maps with model. what might be the issue ?
alamofire version 4.3
You first need to install "AlamofireObjectMapper" .
For which you should add into your project by including "pod 'AlamofireObjectMapper'" followed by command "pod install" .
Now in your API call class "import AlamofireObjectMapper" and try typing ".responseObject" you'll get it.

Web scraping in apple swift 3

I'm a Swift beginner and I'm trying to figure out how to retrieve text from a web article, create a new text file and save the text data into it (Using Swift Playgrounds). Is this possible?
The only thing I could find online regarding the subject was this, and I don't think it is even written for Swift 3:
P.S. If my question needs more details, please let me know instead of putting it on hold. Thanks!
import Cocoa
var url = NSURL(string: "http://finance.yahoo.com/news/tv-news-ces-2017-120931816.html")
if url != nil {
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
print(data)
if error == nil {
var urlContent = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString!
print(urlContent)
That's Swift 2.3. In Swift 3 use URL instead of NSURL and use URLSession rather than NSURLSession, etc. You'd also use String rather than NSString. E.g.
let url = URL(string: "http://finance.yahoo.com/news/tv-news-ces-2017-120931816.html")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
print("\(error)")
return
}
let string = String(data: data, encoding: .utf8)
print("\(string)")
}
task.resume()
If you're going to do this in a playground, remember that this runs asynchronously, so you'll need to set needsIndefiniteExecution.
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
To actually parse the HTML, you should consider using a HTML parser like TFHpple (written in Objective-C, but still works great from Swift) or NDHpple (a Swift version, in which I don't have as much confidence as TFHpple, but probably would work fine).
You might want to see How to Parse HTML on iOS. It's dated, but walks you through the concepts (making sure you're not violating ToS of the web site, how to use the parsers, etc.).
If you want to save this to a file, you can do something like:
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("test.dat")
try! data.write(to: fileURL)
You can use whatever file extension you want.

How to display an image from documents directory to UIImageView in Swift 3?

The below Swift 2 example gives this error:
Value of type String has no member 'stringByAppendingPathComponent'
What do I need to change for Swift 3?
Apple is trying to move everyone off the path-as-string paradigm to URL (i.e. file:///path/to/file.text). The Swift API pretty much removes all path in favor of URL.
You can still find it in Objective-C (NSString):
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let getImagePath = NSString.path(withComponents: [paths, "fileName"])
The more Swifty way:
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = URL(fileURLWithPath: paths).appendingPathComponent("fileName")
I personally like getting of this value from the App delegate. Put this code (stands alone like normal function) into the AppDelegate.swift.
lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)
return urls[urls.count-1]
}()
So in all your files you can use it this way:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let imageUrl = appDelegate.applicationDocumentsDirectory.appendingPathComponent("YourFileName")
let imageUrlString = imageUrl.urlString //if String is needed