How to access variable in Document.swift from another class? - swift

In CoreData document I have an entity SpaceLocation which is set of different SpaceLocations. One of them is default / current one, necessary for editing document.
It's defined in main Document.swift as:
#objc var defaultSpaceLocation: SpaceLocation {
return SpaceLocation.defaultSpaceLocation(in: managedObjectContext!)
}
#objc var currentSpaceLocation: SpaceLocation {
get {
if _currentSpaceLocation == nil {
willChangeValue(for: \Document.currentSpaceLocation)
_currentSpaceLocation = defaultSpaceLocation
didChangeValue(for: \Document.currentSpaceLocation)
}
return _currentSpaceLocation!
}
set {
willChangeValue(for: \Document.currentSpaceLocation)
_currentSpaceLocation = newValue
didChangeValue(for: \Document.currentSpaceLocation)
}
}
and in SpaceLocation class as:
class func defaultSpaceLocation(in moc: NSManagedObjectContext) -> SpaceLocation {
let spaceLocationsRequest = NSFetchRequest<SpaceLocation>(entityName: "SpaceLocation")
var result:SpaceLocation? = nil
do {
let spaceLocations = try moc.fetch(spaceLocationsRequest)
result = spaceLocations.filter {$0.isBaseLocation}.first!
}
catch {
Swift.print("•••• ERROR ••••", #file, #function, "Couldn't get Default Location")
}
return result!
}
}
I access to currentSpaceLocation by:
(NSDocumentController.shared.currentDocument as?Document)?.currentSpaceLocation
but it works only if document is in foreground. When app goes background NSDocumentController.shared.currentDocument becomes nil so I cannot access document.currentSpaceLocation. Any idea how to solve this?

Related

inverse a core data boolean value

In my swift code below the goal would be to inverse whatever the boolean sign is. Right now the code just deletes the current boolean value which is at user1. So say user1 is true when it is inserted in into the function I would like to reverse to false instead of deleting it in core data how do I do that?
class ViewController: UIViewController {
override func viewDidLo
if CoredataHandler.deleteObject(user: user![1]) {
user = CoredataHandler.fetchObject()
print("after single")
for i in user! {
print(i.username!)
}
}
}
}
class CoredataHandler : NSManagedObject {
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
class func fetchObject() -> [User]?
{
let context = getContext()
var user : [User]? = nil
do {
user = try context.fetch(User.fetchRequest())
return user
} catch {
return user
}
}
class func deleteObject(user: User) -> Bool
{
let context = getContext()
let delete = NSBatchDeleteRequest(fetchRequest: User.fetchRequest())
do {
try context.execute(delete)
return true
} catch {
return false
}
}
}

Thread 1 EXC_BAD_ACCESS (code=2, address=0x7ffeeb1aeff8)

I am trying to learn VIPER. I followed this tutorial. I have these Interactor and Presenter:
class PPresenter: ViewToPresenterProtocol {
var view: PresenterToViewProtocol?
var router: PresenterToRouterProtocol? = PRouter()
var interactor: PresenterToInteractorProtocol? = PInteractor()
func initiateFetch() {
interactor?.fetchMatches()
}
func showMatchScreen(navigationC: UIViewController) {
router?.pushToMatchDetailScreen(navigationC: navigationC)
}
}
extension PPresenter: InteractorToPresenterProtocol {
func matchFetched(match: MatchDetails?, banner: Banner?) {
print(match!)
print(banner!)
}
func matchFetchError() {
//TODO
}
}
class PInteractor: PresenterToInteractorProtocol {
var presenter: InteractorToPresenterProtocol? = PPresenter()
var live: Live?
var upcoming: Upcoming?
var banners: Banner?
func fetchMatches() {
let parameters = ["api_token" : Constants.USER_INFO["api_token"].rawValue,"player_id" : Constants.USER_INFO["player_id"].rawValue]
ServiceHelper.sharedInstance.sendRequest(path: "get-predictor", params: parameters, showSpinner: true) { (response, error) in
if let error = error {
print("Unable to fetch match listing",error.localizedDescription)
return
} else {
guard let obj = try? JSONDecoder().decode(MatchDetails.self, from: response.rawData()) else { self.presenter?.matchFetchError(); return }
guard let bannerObj = try? JSONDecoder().decode(Banner.self,from: response.rawData()) else {self.presenter?.matchFetchError(); return }
self.presenter?.matchFetched(match: obj, banner: bannerObj)
}
}
}
}
Now, what is happening here, I get the router working, the view is coming, it is calling presenter, the presenter is calling the interactor, the interactor is successfully calling the API and getting the data and now it is time to return the data received from Interactor to Presenter and here it constantly throwing the following error:
Thread 1 EXC_BAD_ACCESS (code=2, address=0x7ffeeb1aeff8)
I think you have a cyclic call, maybe your interactor is not fully initialized and then you want data from it and then you got "Bad access error".

Blank constant when trying to get list of classes that have adopted a Protocol

I am trying to get a list of classes that have adopted a certain Protocol Migration: Preparation, and then to append those classes into an array. Here is the function in question:
struct Migrations {
static func getMigrations() -> [Preparation.Type] {
var migrationsList = [Preparation.Type]()
var count = UInt32(0)
let classList = objc_copyClassList(&count)!
for i in 0..<Int(count) {
let classInfo = ClassInfo(classList[i])!
if let cls = classInfo.classObject as? Migration.Type {
migrationsList.append(cls)
print(cls.description)
}
}
return migrationsList
}
}
In principle all that should work, but when debugging I note that the classInfo variable is referring to each class in the iteration, but when assigning and casting in the if let as line, the constant cls is always blank - neither a value/class nor nil, just completely blank.
Any idea what I got wrong with that code?
I am also open to suggestions for any better way to get a list of all classes that have adopted a particular protocol...
EDIT: I forgot to provide the code for ClassInfo
import Foundation
struct ClassInfo: CustomStringConvertible, Equatable {
let classObject: AnyClass
let className: String
init?(_ classObject: AnyClass?) {
guard classObject != nil else { return nil }
self.classObject = classObject!
let cName = class_getName(classObject)!
self.className = String(cString: cName)
}
var superclassInfo: ClassInfo? {
let superclassObject: AnyClass? = class_getSuperclass(self.classObject)
return ClassInfo(superclassObject)
}
var description: String {
return self.className
}
static func ==(lhs: ClassInfo, rhs: ClassInfo) -> Bool {
return lhs.className == rhs.className
}
}
I can't explain why cls is always blank, like I said in my comment it's something I run into every time I'm dealing with meta types. As for making the code work as intended, I found this q&a and updated it with Swift 3 to get this code which should cover your situation. It's important to stress that this will only work if you correctly expose Swift to the Objective-C runtime.
Drop this code anywhere and call print(Migrations.getMigrations()) from a convenient entry point.
struct Migrations {
static func getMigrations() -> [Preparation.Type] {
return getClassesImplementingProtocol(p: Preparation.self) as! [Preparation.Type]
}
static func getClassesImplementingProtocol(p: Protocol) -> [AnyClass] {
let classes = objc_getClassList()
var ret = [AnyClass]()
for cls in classes {
if class_conformsToProtocol(cls, p) {
ret.append(cls)
}
}
return ret
}
static func objc_getClassList() -> [AnyClass] {
let expectedClassCount = ObjectiveC.objc_getClassList(nil, 0)
let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(expectedClassCount))
let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(allClasses)
let actualClassCount:Int32 = ObjectiveC.objc_getClassList(autoreleasingAllClasses, expectedClassCount)
var classes = [AnyClass]()
for i in 0 ..< actualClassCount {
if let currentClass: AnyClass = allClasses[Int(i)] {
classes.append(currentClass)
}
}
allClasses.deallocate(capacity: Int(expectedClassCount))
return classes
}
}
class Migration: Preparation {
}
#objc
protocol Preparation {
}

Settings as shared Instance

I tried to do this so get my settings saved whenever the App moves to the background or gets killed or whatever.
I want to access and set the property "useLimits" all over my App.
Why is it not working?
Is there a better more elegant way to achieve this?
import UIKit
class Settings: NSObject
{
static let sharedInstance = Settings()
private let kUseLimits = "kUseLimits"
var useLimits = false
override init()
{
super.init()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(Settings.save),
name: UIApplicationWillResignActiveNotification,
object: nil)
let userdefaults = NSUserDefaults.standardUserDefaults()
self.useLimits = userdefaults.boolForKey(kUseLimits)
}
deinit
{
NSNotificationCenter.defaultCenter().removeObserver(self)
save()
}
func save()
{
let userdefaults = NSUserDefaults.standardUserDefaults()
userdefaults.setBool(self.useLimits, forKey: kUseLimits)
userdefaults.synchronize()
}
func reset()
{
self.useLimits = false
save()
}
}
I think something like this will be good:
class AppSettings {
private struct Keys {
static let useLimits = "AppSttings.useLimits"
}
static var useLimits: Bool {
set {
NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: Keys.useLimits)
}
get {
return NSUserDefaults.standardUserDefaults().boolForKey(Keys.useLimits)
}
}
static func rest() {
useLimits = false
}
}
P.S. Starting from iOS 8 you don't need to call synchronize() in NSUserDefault
P.S.S. NSUserDefaults.standardUserDefaults().boolForKey(Keys.useLimits) will return false if there not such object, if you need specific default value please check on object or use NSUserDefaults.standardUserDefaults().registerDefaults()
P.S.S.S. It wont effect your performance much, so you can read from UD and write there just on on the run, but if you want too performance code, you can do something like this:
private static var _useLimits: Bool?
static var useLimits: Bool {
set {
NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: Keys.useLimits)
_useLimits = newValue
}
get {
if _useLimits == nil {
_useLimits = NSUserDefaults.standardUserDefaults().boolForKey(Keys.useLimits)
}
return _useLimits!
}
}
or more elegant for current value:
private static var _useLimits: Bool = NSUserDefaults.standardUserDefaults().boolForKey(Keys.useLimits)
static var useLimits: Bool {
set {
NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: Keys.useLimits)
_useLimits = newValue
}
get {
return _useLimits
}
}

Swift computed property templates?

Is there a way to template computed properties to avoid repeating the same code over and over? For example, right now I have a class with a block of code that looks like this:
private var _state:State?
private var _maxs:State?
private var _state1s:State?
private var _state10s:State?
var state:State? {
get {
dispatch_semaphore_wait(statephore, DISPATCH_TIME_FOREVER)
let s=_state
dispatch_semaphore_signal(statephore)
return s
}
set {
dispatch_semaphore_wait(statephore, DISPATCH_TIME_FOREVER)
_state=newValue
dispatch_semaphore_signal(statephore)
if newValue != nil {statsTest(newValue!)}
}
}
var maxs:State? {
get {
dispatch_semaphore_wait(maxphore, DISPATCH_TIME_FOREVER)
let m=_maxs
dispatch_semaphore_signal(maxphore)
return m
}
set {
dispatch_semaphore_wait(maxphore, DISPATCH_TIME_FOREVER)
_maxs=newValue
dispatch_semaphore_signal(maxphore)
}
}
var state1s:State? {
get {
dispatch_semaphore_wait(state1sphore, DISPATCH_TIME_FOREVER)
let s=_state1s
dispatch_semaphore_signal(state1sphore)
return s
}
set {
dispatch_semaphore_wait(state1sphore, DISPATCH_TIME_FOREVER)
_state1s=newValue
dispatch_semaphore_signal(state1sphore)
}
}
var state10s:State? {
get {
dispatch_semaphore_wait(state10sphore, DISPATCH_TIME_FOREVER)
let s=_state10s
dispatch_semaphore_signal(state10sphore)
return s
}
set {
dispatch_semaphore_wait(state10sphore, DISPATCH_TIME_FOREVER)
_state10s=newValue
dispatch_semaphore_signal(state10sphore)
}
}
There's an obvious pattern here, and all the repeated code just obfuscates what's happening and has led to errors as I cut/paste/edit/fail. Is there a way I can capture this pattern, and then define my properties with something like:
var state=ProtectedValue(_state,statephore)
?
This looks like a job for generics and inout variables.
func setProtectedValue<T>(inout destination: T, newValue: T, semaphore: SemaphoreType) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
destination = newValue
dispatch_semaphore_signal(semaphore)
}
at the call site:
var state10s:State? {
get {
//...
}
set {
setProtectedValue(&_state10s, newValue, state10sphore)
}
}