Make progress on getting Database.framework to build.

This commit is contained in:
Brent Simmons 2017-07-12 13:25:10 -07:00
parent f46a3ece48
commit e3b8e6833b
14 changed files with 94 additions and 128 deletions

View File

@ -16,7 +16,7 @@ public struct Attachment: Equatable {
public let sizeInBytes: Int? public let sizeInBytes: Int?
public let durationInSeconds: Int? public let durationInSeconds: Int?
init(url: String, mimeType: String?, title: String?, sizeInBytes: Int?, durationInSeconds: Int?) { public init(url: String, mimeType: String?, title: String?, sizeInBytes: Int?, durationInSeconds: Int?) {
self.url = url self.url = url
self.mimeType = mimeType self.mimeType = mimeType

View File

@ -0,0 +1,21 @@
//
// AccountInfo.swift
// Database
//
// Created by Brent Simmons on 7/3/17.
// Copyright © 2017 Ranchero Software. All rights reserved.
//
import Foundation
import RSCore
import RSDatabase
// AccountInfo is a plist-compatible dictionary thats stored as a binary plist in the database.
func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
return nil
}
return propertyList(withData: rawAccountInfo) as? AccountInfo
}

View File

@ -51,5 +51,10 @@ public struct DatabaseKey {
// Tag // Tag
static let tagName = "tagName" static let tagName = "tagName"
// Author
static let name = "name"
static let avatarURL = "avatarURL"
static let emailAddress = "emailAddress"
} }

View File

@ -9,7 +9,7 @@ CREATE TABLE if not EXISTS tags(tagName TEXT NOT NULL, articleID TEXT NOT NULL,
CREATE TABLE if not EXISTS attachments(articleID TEXT NOT NULL, url TEXT NOT NULL, mimeType TEXT, title TEXT, sizeInBytes INTEGER, durationInSeconds INTEGER, PRIMARY KEY(articleID, url)); CREATE TABLE if not EXISTS attachments(articleID TEXT NOT NULL, url TEXT NOT NULL, mimeType TEXT, title TEXT, sizeInBytes INTEGER, durationInSeconds INTEGER, PRIMARY KEY(articleID, url));
CREATE INDEX if not EXISTS feedIndex on articles (feedID); CREATE INDEX if not EXISTS articles_feedID_index on articles (feedID);
CREATE INDEX if not EXISTS tags_tagName_index on tags(tagName COLLATE NOCASE); CREATE INDEX if not EXISTS tags_tagName_index on tags(tagName COLLATE NOCASE);

View File

@ -222,16 +222,16 @@ private extension Database {
let oneArticleDictionary = oneDictionary.mutableCopy() as! NSMutableDictionary let oneArticleDictionary = oneDictionary.mutableCopy() as! NSMutableDictionary
let articleID = oneArticleDictionary[DatabaseKey.articleID]! let articleID = oneArticleDictionary[DatabaseKey.articleID]!
oneArticleDictionary.removeObject(forKey: articleIDKey) oneArticleDictionary.removeObject(forKey: DatabaseKey.articleID)
let _ = database.rs_updateRows(with: oneArticleDictionary as [NSObject: AnyObject], whereKey: articleIDKey, equalsValue: articleID, tableName: articlesTableName) let _ = database.rs_updateRows(with: oneArticleDictionary as [NSObject: AnyObject], whereKey: DatabaseKey.articleID, equalsValue: articleID, tableName: DatabaseTableName.articles)
} }
} }
if !newArticleDictionaries.isEmpty { if !newArticleDictionaries.isEmpty {
for oneNewArticleDictionary in newArticleDictionaries { for oneNewArticleDictionary in newArticleDictionaries {
let _ = database.rs_insertRow(with: oneNewArticleDictionary as [NSObject: AnyObject], insertType: RSDatabaseInsertOrReplace, tableName: articlesTableName) let _ = database.rs_insertRow(with: oneNewArticleDictionary as [NSObject: AnyObject], insertType: RSDatabaseInsertOrReplace, tableName: DatabaseTableName.articles)
} }
} }
} }
@ -256,7 +256,7 @@ private extension Database {
var d = [String: AnyObject]() var d = [String: AnyObject]()
for oneArticle in articles { for oneArticle in articles {
let oneArticleID = (oneArticle as AnyObject).value(forKey: articleIDKey) as! String let oneArticleID = (oneArticle as AnyObject).value(forKey: DatabaseKey.articleID) as! String
d[oneArticleID] = oneArticle as AnyObject d[oneArticleID] = oneArticle as AnyObject
} }
return d return d

View File

@ -10,7 +10,7 @@
844BEE411F0AB3AB004AB7CD /* Database.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844BEE371F0AB3AA004AB7CD /* Database.framework */; }; 844BEE411F0AB3AB004AB7CD /* Database.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844BEE371F0AB3AA004AB7CD /* Database.framework */; };
844BEE461F0AB3AB004AB7CD /* DatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE451F0AB3AB004AB7CD /* DatabaseTests.swift */; }; 844BEE461F0AB3AB004AB7CD /* DatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BEE451F0AB3AB004AB7CD /* DatabaseTests.swift */; };
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580661F0AEBCD003CCFA1 /* Constants.swift */; }; 845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580661F0AEBCD003CCFA1 /* Constants.swift */; };
845580721F0AEE49003CCFA1 /* PropertyListTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580711F0AEE49003CCFA1 /* PropertyListTransformer.swift */; }; 845580721F0AEE49003CCFA1 /* AccountInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580711F0AEE49003CCFA1 /* AccountInfo.swift */; };
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580751F0AF670003CCFA1 /* Article+Database.swift */; }; 845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580751F0AF670003CCFA1 /* Article+Database.swift */; };
845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580771F0AF678003CCFA1 /* Folder+Database.swift */; }; 845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580771F0AF678003CCFA1 /* Folder+Database.swift */; };
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */; }; 8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */; };
@ -113,7 +113,7 @@
844BEE451F0AB3AB004AB7CD /* DatabaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseTests.swift; sourceTree = "<group>"; }; 844BEE451F0AB3AB004AB7CD /* DatabaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseTests.swift; sourceTree = "<group>"; };
844BEE471F0AB3AB004AB7CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 844BEE471F0AB3AB004AB7CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
845580661F0AEBCD003CCFA1 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; }; 845580661F0AEBCD003CCFA1 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
845580711F0AEE49003CCFA1 /* PropertyListTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertyListTransformer.swift; sourceTree = "<group>"; }; 845580711F0AEE49003CCFA1 /* AccountInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountInfo.swift; sourceTree = "<group>"; };
845580751F0AF670003CCFA1 /* Article+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Article+Database.swift"; path = "Extensions/Article+Database.swift"; sourceTree = "<group>"; }; 845580751F0AF670003CCFA1 /* Article+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Article+Database.swift"; path = "Extensions/Article+Database.swift"; sourceTree = "<group>"; };
845580771F0AF678003CCFA1 /* Folder+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Folder+Database.swift"; path = "Extensions/Folder+Database.swift"; sourceTree = "<group>"; }; 845580771F0AF678003CCFA1 /* Folder+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Folder+Database.swift"; path = "Extensions/Folder+Database.swift"; sourceTree = "<group>"; };
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "ArticleStatus+Database.swift"; path = "Extensions/ArticleStatus+Database.swift"; sourceTree = "<group>"; }; 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "ArticleStatus+Database.swift"; path = "Extensions/ArticleStatus+Database.swift"; sourceTree = "<group>"; };
@ -206,7 +206,7 @@
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */, 845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */,
8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */, 8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */,
84BB4BA31F119D4A00858766 /* Author+Database.swift */, 84BB4BA31F119D4A00858766 /* Author+Database.swift */,
845580711F0AEE49003CCFA1 /* PropertyListTransformer.swift */, 845580711F0AEE49003CCFA1 /* AccountInfo.swift */,
); );
name = Extensions; name = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@ -462,7 +462,7 @@
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */, 845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */,
845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */, 845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */,
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */, 845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
845580721F0AEE49003CCFA1 /* PropertyListTransformer.swift in Sources */, 845580721F0AEE49003CCFA1 /* AccountInfo.swift in Sources */,
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */, 8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
84BB4BA41F119D4A00858766 /* Author+Database.swift in Sources */, 84BB4BA41F119D4A00858766 /* Author+Database.swift in Sources */,
84BB4BA91F11A32800858766 /* TagsManager.swift in Sources */, 84BB4BA91F11A32800858766 /* TagsManager.swift in Sources */,

View File

@ -35,9 +35,9 @@ extension Article {
let authors = PropertyListTransformer.authorsWithRow(row) let authors = PropertyListTransformer.authorsWithRow(row)
let tags = PropertyListTransformer.tagsWithRow(row) let tags = PropertyListTransformer.tagsWithRow(row)
let attachments = PropertyListTransformer.attachmentsWithRow(row) let attachments = PropertyListTransformer.attachmentsWithRow(row)
let accountInfo = PropertyListTransformer.accountInfoWithRow(row) let accountInfo = accountInfoWithRow(row)
self.init(account: account, feedID: feed, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo] self.init(account: account, feedID: feed, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo)
} }
func databaseDictionary() -> NSDictionary { func databaseDictionary() -> NSDictionary {

View File

@ -27,7 +27,7 @@ extension ArticleStatus {
dateArrived = NSDate.distantPast dateArrived = NSDate.distantPast
} }
let accountInfoPlist = PropertyListTransformer.accountInfoWithRow(row) let accountInfoPlist = accountInfoWithRow(row)
self.init(articleID: articleID!, read: read, starred: starred, userDeleted: userDeleted, dateArrived: dateArrived!, accountInfo: accountInfoPlist) self.init(articleID: articleID!, read: read, starred: starred, userDeleted: userDeleted, dateArrived: dateArrived!, accountInfo: accountInfoPlist)
} }

View File

@ -7,22 +7,24 @@
// //
import Foundation import Foundation
import Data
extension Attachment { extension Attachment {
convenience init?(databaseDictionary d: [String: Any]) { init?(databaseDictionary d: [String: Any]) {
guard let url = d[DatabaseKey.url] as? String else { guard let url = d[DatabaseKey.url] as? String else {
return nil return nil
} }
let mimeType = d[DatabaseKey.mimeType] as? String let mimeType = d[DatabaseKey.mimeType] as? String
let title = d[DatabaseKey.title] as? String let title = d[DatabaseKey.title] as? String
let sizeInBytes = d[DatabaseKey.sizeInBytes] as? Int
let durationInSeconds = d[DatabaseKey.durationInSeconds] as? Int let durationInSeconds = d[DatabaseKey.durationInSeconds] as? Int
self.init(url: url, mimeType: mimeType, title: title, durationInSeconds: durationInSeconds) self.init(url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
} }
class func attachments(with plist: [Any]) -> [Attachment]? { static func attachments(with plist: [Any]) -> [Attachment]? {
return plist.flatMap{ (oneDictionary) -> Attachment? in return plist.flatMap{ (oneDictionary) -> Attachment? in
if let d = oneDictionary as? [String: Any] { if let d = oneDictionary as? [String: Any] {

View File

@ -7,33 +7,18 @@
// //
import Foundation import Foundation
import Data
import RSDatabase
extension Author { extension Author {
private static let init?(row: FMResultSet) {
convenience init?(databaseDictionary d: [String: Any]) {
guard let url = d[DatabaseKey.url] as? String else {
return nil
}
let mimeType = d[DatabaseKey.mimeType] as? String
let title = d[DatabaseKey.title] as? String
let durationInSeconds = d[DatabaseKey.durationInSeconds] as? Int
self.init(url: url, mimeType: mimeType, title: title, durationInSeconds: durationInSeconds)
let name = row.string(forColumn: DatabaseKey.name)
let url = row.string(forColumn: DatabaseKey.url)
let avatarURL = row.string(forColumn: DatabaseKey.avatarURL)
let emailAddress = row.string(forColumn: DatabaseKey.emailAddress)
self.init(name: name, url: url, avatarURL: avatarURL, emailAddress: emailAddress) self.init(name: name, url: url, avatarURL: avatarURL, emailAddress: emailAddress)
} }
class func attachments(with plist: [Any]) -> [Attachment]? {
return plist.flatMap{ (oneDictionary) -> Attachment? in
if let d = oneDictionary as? [String: Any] {
return Attachment(databaseDictionary: d)
}
return nil
}
}
} }

View File

@ -1,84 +0,0 @@
//
// AccountInfo.swift
// Database
//
// Created by Brent Simmons on 7/3/17.
// Copyright © 2017 Ranchero Software. All rights reserved.
//
import Foundation
import RSDatabase
import Data
// This allows for serializing structures such as Author, Attachment, and AccountInfo
// without having to create separate tables and lookup tables.
// While there are good strong arguments for using separate tables,
// we decided that the relative simplicity this allows is worth it.
struct PropertyListTransformer {
static func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
return nil
}
return propertyList(withData: rawAccountInfo) as? AccountInfo
}
static func tagsWithRow(_ row: FMResultSet) -> [String]? {
guard let d = row.data(forColumn: DatabaseKey.tags) else {
return nil
}
return propertyList(withData: d) as? [String]
}
static func attachmentsWithRow(_ row: FMResultSet) -> [Attachment]? {
guard let d = row.data(forColumn: DatabaseKey.attachments) else {
return nil
}
guard let plist = propertyList(withData: d) as? [Any] else {
return nil
}
return Attachment.attachments(with: plist)
}
static func authorsWithRow(_ row: FMResultSet) -> [Author]? {
guard let d = row.data(forColumn: DatabaseKey.authors) else {
return nil
}
guard let plist = propertyList(withData: d) as? [Any] else {
return nil
}
return Author.authors(with: plist)
}
static func propertyListWithRow(_ row: FMResultSet, column: String) -> Any? {
guard let rawData = row.data(forColumn: column) else {
return nil
}
return propertyList(withData: rawData)
}
static func propertyList(withData data: Data) -> Any? {
do {
return try PropertyListSerialization.propertyList(fromData: rawAccountInfo, options: [], format: nil)
} catch {
return nil
}
}
static func data(withPropertyList plist: Any) -> Data? {
do {
return try PropertyListSerialization.data(from: plist, format: .binary, options: [])
}
catch {
return nil
}
}
}

View File

@ -8,15 +8,18 @@
import Foundation import Foundation
import RSDatabase import RSDatabase
import Data
// Tags  and the non-existence of tags are cached, once fetched, for the lifetime of the run. // Tags  and the non-existence of tags are cached, once fetched, for the lifetime of the run.
// This uses some extra memory but cuts way down on the amount of database time spent // This uses some extra memory but cuts way down on the amount of database time spent
// maintaining the tags table. // maintaining the tags table.
typealias TagNameSet = Set<String>
final class TagsManager { final class TagsManager {
private var articleIDCache = [String: <String>]() // articleID: tag private var articleIDCache = [String: TagNameSet]() // articleID: tags
private var articleIDsWithNoTags = Set<String>() private var articleIDsWithNoTags = TagNameSet()
private let queue: RSDatabaseQueue private let queue: RSDatabaseQueue
@ -53,8 +56,6 @@ final class TagsManager {
} }
} }
typealias TagNameSet = Set<String>
private extension TagsManager { private extension TagsManager {
func cacheTagsForArticle(_ article: Article, tags: TagNameSet) { func cacheTagsForArticle(_ article: Article, tags: TagNameSet) {
@ -183,7 +184,7 @@ private extension TagsManager {
} }
} }
func fetchTagsForArticleIDs(_ articleIDs: Set<String>, database: FMDatabase) -> TagsTable] { func fetchTagsForArticleIDs(_ articleIDs: Set<String>, database: FMDatabase) -> TagsTable {
var tagSpecifiers = TagsTable() var tagSpecifiers = TagsTable()
@ -193,7 +194,7 @@ private extension TagsManager {
while rs.next() { while rs.next() {
guard let oneTagName = rs.string(forColumn: DatabaseKey.tagName), oneArticleID = rs.string(forColumn: DatabaseKey.articleID) else { guard let oneTagName = rs.string(forColumn: DatabaseKey.tagName), let oneArticleID = rs.string(forColumn: DatabaseKey.articleID) else {
continue continue
} }
if tagSpecifiers[oneArticleID] == nil { if tagSpecifiers[oneArticleID] == nil {

View File

@ -135,6 +135,7 @@
84CFF56A1AC3D1B000CEA6C8 /* RSScaling.m in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF5681AC3D1B000CEA6C8 /* RSScaling.m */; }; 84CFF56A1AC3D1B000CEA6C8 /* RSScaling.m in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF5681AC3D1B000CEA6C8 /* RSScaling.m */; };
84CFF56D1AC3D20A00CEA6C8 /* NSImage+RSCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CFF56B1AC3D20A00CEA6C8 /* NSImage+RSCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84CFF56D1AC3D20A00CEA6C8 /* NSImage+RSCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CFF56B1AC3D20A00CEA6C8 /* NSImage+RSCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
84CFF56E1AC3D20A00CEA6C8 /* NSImage+RSCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF56C1AC3D20A00CEA6C8 /* NSImage+RSCore.m */; }; 84CFF56E1AC3D20A00CEA6C8 /* NSImage+RSCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 84CFF56C1AC3D20A00CEA6C8 /* NSImage+RSCore.m */; };
84F20F831F16BA6200D8E682 /* PropertyList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F20F821F16BA6200D8E682 /* PropertyList.swift */; };
84FE9FC31C00453900081CE9 /* NSStoryboard+RSCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FE9FC11C00453900081CE9 /* NSStoryboard+RSCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84FE9FC31C00453900081CE9 /* NSStoryboard+RSCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FE9FC11C00453900081CE9 /* NSStoryboard+RSCore.h */; settings = {ATTRIBUTES = (Public, ); }; };
84FE9FC41C00453900081CE9 /* NSStoryboard+RSCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FE9FC21C00453900081CE9 /* NSStoryboard+RSCore.m */; }; 84FE9FC41C00453900081CE9 /* NSStoryboard+RSCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FE9FC21C00453900081CE9 /* NSStoryboard+RSCore.m */; };
84FEB4AC1D19D7F4004727E5 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */; }; 84FEB4AC1D19D7F4004727E5 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */; };
@ -234,6 +235,7 @@
84CFF5681AC3D1B000CEA6C8 /* RSScaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSScaling.m; sourceTree = "<group>"; }; 84CFF5681AC3D1B000CEA6C8 /* RSScaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSScaling.m; sourceTree = "<group>"; };
84CFF56B1AC3D20A00CEA6C8 /* NSImage+RSCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+RSCore.h"; sourceTree = "<group>"; }; 84CFF56B1AC3D20A00CEA6C8 /* NSImage+RSCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+RSCore.h"; sourceTree = "<group>"; };
84CFF56C1AC3D20A00CEA6C8 /* NSImage+RSCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+RSCore.m"; sourceTree = "<group>"; }; 84CFF56C1AC3D20A00CEA6C8 /* NSImage+RSCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+RSCore.m"; sourceTree = "<group>"; };
84F20F821F16BA6200D8E682 /* PropertyList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyList.swift; sourceTree = "<group>"; };
84FE9FC11C00453900081CE9 /* NSStoryboard+RSCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSStoryboard+RSCore.h"; sourceTree = "<group>"; }; 84FE9FC11C00453900081CE9 /* NSStoryboard+RSCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSStoryboard+RSCore.h"; sourceTree = "<group>"; };
84FE9FC21C00453900081CE9 /* NSStoryboard+RSCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSStoryboard+RSCore.m"; sourceTree = "<group>"; }; 84FE9FC21C00453900081CE9 /* NSStoryboard+RSCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSStoryboard+RSCore.m"; sourceTree = "<group>"; };
84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; }; 84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
@ -377,6 +379,7 @@
84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */, 84FEB4AB1D19D7F4004727E5 /* Date+Extensions.swift */,
84BB45421D6909C700B48537 /* NSMutableDictionary-Extensions.swift */, 84BB45421D6909C700B48537 /* NSMutableDictionary-Extensions.swift */,
8414CBA61C95F2EA00333C12 /* Set+Extensions.swift */, 8414CBA61C95F2EA00333C12 /* Set+Extensions.swift */,
84F20F821F16BA6200D8E682 /* PropertyList.swift */,
); );
name = Foundation; name = Foundation;
path = RSCore; path = RSCore;
@ -686,6 +689,7 @@
8432B1861DACA0E90057D6DF /* NSResponder-Extensions.swift in Sources */, 8432B1861DACA0E90057D6DF /* NSResponder-Extensions.swift in Sources */,
849B08981BF7BCE30090CEE4 /* NSPasteboard+RSCore.m in Sources */, 849B08981BF7BCE30090CEE4 /* NSPasteboard+RSCore.m in Sources */,
842635571D7FA1C800196285 /* NSTableView+Extensions.swift in Sources */, 842635571D7FA1C800196285 /* NSTableView+Extensions.swift in Sources */,
84F20F831F16BA6200D8E682 /* PropertyList.swift in Sources */,
84CFF5611AC3D0CE00CEA6C8 /* RSBinaryCache.m in Sources */, 84CFF5611AC3D0CE00CEA6C8 /* RSBinaryCache.m in Sources */,
84CFF5301AC3CB1900CEA6C8 /* NSDate+RSCore.m in Sources */, 84CFF5301AC3CB1900CEA6C8 /* NSDate+RSCore.m in Sources */,
84CFF5281AC3C9A200CEA6C8 /* NSArray+RSCore.m in Sources */, 84CFF5281AC3C9A200CEA6C8 /* NSArray+RSCore.m in Sources */,

View File

@ -0,0 +1,32 @@
//
// PropertyList.swift
// RSCore
//
// Created by Brent Simmons on 7/12/17.
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
//
import Foundation
// These functions eat errors.
public func propertyList(withData data: Data) -> Any? {
do {
return try PropertyListSerialization.propertyList(from: data, options: [], format: nil)
} catch {
return nil
}
}
// Create a binary plist.
public func data(withPropertyList plist: Any) -> Data? {
do {
return try PropertyListSerialization.data(fromPropertyList: plist, format: .binary, options: 0)
}
catch {
return nil
}
}