Saving custom object as core data property - swift

I am trying to save a custom class as a property of a core data object.
The Core Data object:
#objc(Safer)
class Safer: NSObject
{
#NSManaged var perakimFiles: [prayer]? //This line gives me an error saying that it cannot save a type that is not Obj. C
#NSManaged var titleEnglish: String?
#NSManaged var titleHebrew: String?
#NSManaged var parshaPerakim: [Int]?
#NSManaged var saferCode: String?
var titles: [[String]]
{
get
{
var ret = [[String]]()
var i = 0
for file in perakimFiles!
{
ret.append([file.title, "\(i+1)"])
i++
}
return ret
}
}
init(_ _saferCode: SefarimCodes)
{
super.init()
self.saferCode = _saferCode.rawValue
}
init(_perakimFiles: [prayer], _titleEnglish: String, _titleHebrew: String)
{
super.init()
self.perakimFiles = _perakimFiles
self.titleEnglish = _titleEnglish
self.titleHebrew = _titleHebrew
}
init(_perakimFiles: [prayer], _titleEnglish: String, _titleHebrew: String, _parshaPerakim: [Int])
{
super.init()
self.perakimFiles = _perakimFiles
self.titleEnglish = _titleEnglish
self.titleHebrew = _titleHebrew
self.parshaPerakim = _parshaPerakim
self.saferCode = setTorahSaferCode()!.rawValue
let config = self.configFromCode()
self.perakimFiles = config.perakimFiles
}
}
Here is the prayer class that I am trying to save in the core data object:
class prayer
{
var url: NSURL
var title: String
var detail: String?
init(initURL: NSURL, initTitle: String)
{
print("1")
print("2")
self.title = initTitle
print("3")
self.url = initURL
print("4")
}
init(initURL: NSURL, initTitle: String, initDetail: String)
{
self.url = initURL
self.title = initTitle
self.detail = initTitle
}
}
So what can I do to the prayer class to make it savable by the core data object? I need to also be able to use instances of the prayer class in other places of the code.

As mentioned, have your prayer class subclass NSObject and conform to NSCoding which requires two methods : -initWithCoder: and encodeWithCoder:
Once those are implemented, you can use NSKeyedArchiver/NSKeyedUnarchiver class methods to transform your objects into NSData objects and back, thus allowing you to store your objects as CoreData properties under the supported NSData type.

Let class prayer conforms to NSObject and NSCoding and see whether that addresses the error.

Related

Using lazy variable vs. Initializing - Swift

I'm making an app with thousands of inputs.
I have a model class like this
class Waterz {
var id: String = ""
var entitle: String? = nil
var artitle: String? = nil
var date: [String]? = nil
var frequency: [daysOfWeek]? = nil
var subMenus: Array<Waterz>? = nil
var location: String? = nil
var audio: [reciterNames]? = nil
var menuIcon: String? = nil
init() {
}
convenience init(id: String, entitle: String, artitle: String, date: [String]?, frequency: [daysOfWeek]?, location: String?, audio: [reciterNames]?) {
self.init()
self.id = id
self.entitle = entitle
self.artitle = artitle
self.date = date
self.frequency = frequency
self.location = location
self.audio = audio
}
}
And then I have my filling-up class. My filling up class has thousands of variables, so I wanted to see if I should use lazy vars or declare each variable, then initialize it in the init() like this
class Database {
var duaKumayl: Waterz
init() {
duaKumayl = .init(...)
}
}
Or should I use lazy vars? Using my current method of declaring then initializing will take forever because I have thousands of variables.
Try to do pagination within app , if you have thousands of variables . This will reduce the show up time for the data you are presenting in UI.
In such cases as i mentioned above , you should use initialization . But if your evaluation of data takes too long use lazy variables.

Function accepting generic parameters

I have a subclass of NSManagedObject. I'm using a protocol to create a "wrapper" class. In my controller the data can be either: Items or Item1. To be able to use my function I'll have to add the protocol ItemInfo to Items but that means I'll have to add
var items: Items { return self }
in Items, which seems a bit redundant. I've tried creating a base class but that didn't work.
Question:
Is there a better way to let my function accept both Items and Item1 as parameter like using generics?
NSManagedObject:
class Items: NSManagedObject {
#NSManaged var name: String
#NSManaged var code: String
}
Protocol:
protocol ItemInfo {
var item: Items { get }
}
extension ItemInfo {
var name : String { return item.name }
var code : String { return item.code }
}
Wrapper:
class Item1: ItemInfo {
let item: Items
init(item: Items) { self.item = item }
}
function:
func handleItem(item: ItemInfo) {
print(item.name)
print(item.code)
}
I could use:
func handleItem<T>(item: T) {
if let a = item as? Items {
print(a.name)
print(a.code)
}
if let a = item as? ItemInfo {
print(a.name)
print(a.code)
}
}
But this doesn't seem the right way ...
If I understand correctly what you are trying to achieve (function accepting two kind of items), I would use protocol as type accepted by function, refer the code below
class Items: NSManagedObject, ItemInfo {
#NSManaged var name: String
#NSManaged var code: String
}
class Item1: NSManagedObject, ItemInfo {
#NSManaged var name: String
#NSManaged var code: String
}
protocol ItemInfo {
var name: String {get set}
var code: String {get set}
}
and function would look like this
func handle(item: ItemInfo) {
print(item.code)
print(item.name)
}

Type casting in a generic swift function

Supposing I have a UICollectionViewCell and a UITableViewCell with identical properties. Rather than have two functions which populate those cells, could I have a generic that takes something , determine what that was and then cast it to the correct thing to perform actions on it before returning?
my thinking is:
func setUpCell<T>(event: Event, cell:T) -> T {
// figure out what T is and cast it
cell.event.bar = event.bar
return cell
}
is this a good way of avoiding large amounts of code duplication?
Given your model type
struct Event {
let title: String
let desc: String
}
define this protocol
protocol EventCell: class {
var id: String? { get set }
var desc: String? { get set }
}
Now conform your UITabelViewCell and UICollectionViewCell to it
class TableCell: UITableViewController, EventCell {
var id: String?
var desc: String?
}
class CollectionCell: UICollectionViewCell, EventCell {
var id: String?
var desc: String?
}
And finally define this extension
extension EventCell {
func populate(event:Event) {
self.id = event.id
self.desc = event.desc
}
}
That's it. Now both your cells (UITabelViewCell and UICollectionViewCell) have the populate method!
Does this match what you were thinking?
import UIKit
struct Event {
var bar:Int = 0
}
// Protocol to group common additions
protocol ViewCellAdditions {
init()
var separatorInset:Int { get set }
var event:Event { get set}
}
// Generic function to work on any class that adopts ViewCellAdditions
func setUpCell<T: ViewCellAdditions>(event: Event, cell:T, foo:Int) -> T {
var newCell = T()
newCell.separatorInset = foo
newCell.event.bar = event.bar
return newCell
}
// Class that adopts ViewCellAdditions
class NewCellClass: ViewCellAdditions {
required init() {}
var separatorInset:Int = 10
var event:Event = Event()
}
// How to use it
let aCell = NewCellClass()
let aEvent = Event()
let newCell = setUpCell(aEvent, cell: aCell, foo: 5)

How do I create global object in swift?

I think my previous question was too vague. Let me try again.
I'm trying to hold user information by creating a singleton.
After a bit of research, this is what I understood.
Class UserInfo {
var userFirstName: String?
var userLastName: String?
/*I'll add all other variables here*/
}
let sharedInfo = UserInfo()
Am I on right path?
EDIT: For Swift 1.2 and higher (Thanks Will M)
class UserInfo {
static let sharedUserInfo = UserInfo()
var firstName: String?
var lastName: String?
}
For Swift earlier than 1.2
Something along the lines of:
class UserInfo
{
// Singleton Setup
private static var info: UserInfo?
class func sharedUserInfo() -> UserInfo
{
if self.info == nil
{
self.info = UserInfo()
}
return self.info!
}
// Class properties
var firstName: String?
var lastName: String?
}
let user = UserInfo.sharedUserInfo()
user.firstName = "Fred"
user.lastName = "Smith"
I would also recommend making sure that a singleton is really what you want, because depending on how you use it, you could run into some race conditions with threading.

Get "does not implement methodSignatureForSelector" when try to store Array in NSUserDefaults,Swift?

I try to store Array of objects in NSUserDefaults.
I have following snippets of code:
var accounts = MyAccounts()
var array:Array<MyAccounts.MyCalendar> = accounts.populateFromCalendars()
NSUserDefaults.standardUserDefaults().
setObject(array, forKey: "test_storeAccounts_array") // <- get error here
NSUserDefaults.standardUserDefaults().synchronize()
But I get Exception:
does not implement methodSignatureForSelector: -- trouble ahead
my class structure:
class MyAccounts {
/* ... */
class MyCalendar {
var title:String?
var identifier:String?
var email:String?
var calType:String?
var isActive:Bool?
var isMainAcount:Bool?
init(){}
}
}
Any ideas?
Make sure your class inherits from NSObject
class MyAccounts:NSObject {
/* ... */
class MyCalendar {
var title:String?
var identifier:String?
var email:String?
var calType:String?
var isActive:Bool?
var isMainAcount:Bool?
init(){}
}
}
I was getting this exception in Swift 3.0. In my case, my model class was not inherit from NSObject base class. just inherit my class from NSObject base class and implements NSCoding protocol (if your container array has custom objects)
class Stock: NSObject, NSCoding {
var stockName: String?
override init() {
}
//MARK: NSCoding protocol methods
func encode(with aCoder: NSCoder){
aCoder.encode(self.stockName, forKey: "name")
}
required init(coder decoder: NSCoder) {
if let name = decoder.decodeObject(forKey: "name") as? String{
self.stockName = name
}
}
func getStockDataFromDict(stockDict stockDict:[String:AnyObject]) -> Stock {
if let stockName = stockDict["name"] {
self.stockName = stockName as? String
}
return self
}
}
In Swift 2, I experienced similar error while using the Notification Pattern within a custom class. Note that when the same notification(Observe) is implemented in a ViewController class , it doesn't complain. Its only with the custom class, created from a Swift file without subclassing this error was thrown
class myClass : NSObject {
override init(){
super.init()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("functionCall:"), name: "NotificationName", object: nil)
}
//Implement function
func functionCall(notification: NSNotification) {
//Extract the object and implement the function
}
}
You need to convert the class into NSData first. Something like this:
var data = NSKeyedArchiver.archivedDataWithRootObject(accounts.populateFromCalendars())
var userDefaults = NSUserDefaults.standardUserDefaults();
userDefaults.setObject(data, forKey: "test_storeAccounts_array");