Swift generic table view data source and delegate, protocol backed NSManagedObjects, cannot obtain entity attribute, runtime error
The Problem
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]:
this class is not key value coding-compliant for the key active.'
Thanks to @GrahamPerks answer to this SO question, I inserted an exception breakpoint in my code, which now pauses execution at this line...
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool // <-- PAUSES AT THIS LINE
This obviously needs further explanation...
Background
I'm writing a Core Data app that uses a generic table view data source and delegate, more or less set up per Florian Kugler's book "Core Data", published in 2017 by objc.io.
I have successfully linked three separate UITableViewController
s to this generic data source / delegate. I am using a single main storyboard and these three controllers are linked to three UISplitViewController
master/detail views.
I have deleted the automatically generated dataSource and delegate connections within the storyboard UITableView
s (although whether I leave or remove these connections, seems to make no difference).
If I comment out the code for the static var entityActive
above, the project will successfully Build and Run.
My code uses the UITableViewDelegate
method tableView(_, willDisplay:, forRowAt:)
to change the .textColor
of text and .backgroundColor
of cells, based on an attribute "active", stored as a boolean Scalar Type value with each entity.
For clarity, I'm trying to get the "active" attribute (every entity in my data model has a common attribute "active") for each NSManagedObject
for the entity. The value of that "active" attribute (Bool
true
or false
) for each entity is then used to format the cell in the if...else statement in the following code.
To attempt to maximise code reuse and minimise code repetition, I have also placed this delegate method in my generic data source / delegate class.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let entityObjectActive = T.entityActive
if entityObjectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
The compiler doesn't complain.
I seem to be able to use the generic type T
(representing Core Data entities) to associate the static property entityActive
with my instance of entityObjectActive
- so this seems to work...
let entityObjectActive = T.entityActive
To confirm, I have the following:
generic data source class....
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
protocol...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
static var entityActive: Bool get
}
and extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool
Attempts at Problem Solving
I've done some reading attempting to resolve my problem, including a review of many blogs (on how to set up generics in general and generic table view data sources) and a lot of SO Q&A, in particular...
How to fix Error: this class is not key value coding-compliant for the key tableView.'
Uncaught exception: This class is not key value coding-compliant
setValue:forUndefinedKey: this class is not key value coding-compliant for the key
It seems that all the SO Q&A are directly related to an issue with IB connections within storyboards. Maybe this is my issue too - but if that is the case it seems to me to be very well hidden.
Any assistance or advice please?
PS: I'm learning Swift after being a long time coder in Obj-C and I'm really struggling with the Generics Protocols Extensions paradigm shift, so it could be that my use of generic types is incorrect?
ios swift uitableview generics core-data
|
show 1 more comment
The Problem
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]:
this class is not key value coding-compliant for the key active.'
Thanks to @GrahamPerks answer to this SO question, I inserted an exception breakpoint in my code, which now pauses execution at this line...
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool // <-- PAUSES AT THIS LINE
This obviously needs further explanation...
Background
I'm writing a Core Data app that uses a generic table view data source and delegate, more or less set up per Florian Kugler's book "Core Data", published in 2017 by objc.io.
I have successfully linked three separate UITableViewController
s to this generic data source / delegate. I am using a single main storyboard and these three controllers are linked to three UISplitViewController
master/detail views.
I have deleted the automatically generated dataSource and delegate connections within the storyboard UITableView
s (although whether I leave or remove these connections, seems to make no difference).
If I comment out the code for the static var entityActive
above, the project will successfully Build and Run.
My code uses the UITableViewDelegate
method tableView(_, willDisplay:, forRowAt:)
to change the .textColor
of text and .backgroundColor
of cells, based on an attribute "active", stored as a boolean Scalar Type value with each entity.
For clarity, I'm trying to get the "active" attribute (every entity in my data model has a common attribute "active") for each NSManagedObject
for the entity. The value of that "active" attribute (Bool
true
or false
) for each entity is then used to format the cell in the if...else statement in the following code.
To attempt to maximise code reuse and minimise code repetition, I have also placed this delegate method in my generic data source / delegate class.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let entityObjectActive = T.entityActive
if entityObjectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
The compiler doesn't complain.
I seem to be able to use the generic type T
(representing Core Data entities) to associate the static property entityActive
with my instance of entityObjectActive
- so this seems to work...
let entityObjectActive = T.entityActive
To confirm, I have the following:
generic data source class....
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
protocol...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
static var entityActive: Bool get
}
and extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool
Attempts at Problem Solving
I've done some reading attempting to resolve my problem, including a review of many blogs (on how to set up generics in general and generic table view data sources) and a lot of SO Q&A, in particular...
How to fix Error: this class is not key value coding-compliant for the key tableView.'
Uncaught exception: This class is not key value coding-compliant
setValue:forUndefinedKey: this class is not key value coding-compliant for the key
It seems that all the SO Q&A are directly related to an issue with IB connections within storyboards. Maybe this is my issue too - but if that is the case it seems to me to be very well hidden.
Any assistance or advice please?
PS: I'm learning Swift after being a long time coder in Obj-C and I'm really struggling with the Generics Protocols Extensions paradigm shift, so it could be that my use of generic types is incorrect?
ios swift uitableview generics core-data
1
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed asManaged.entity
when it's static?
– Joakim Danielson
Nov 13 '18 at 6:33
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
1
Per your extension,entity
is anNSEntityDescription
: there's noactive
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get theactive
attribute for the NSManagedObject?
– pbasdf
Nov 13 '18 at 10:39
@pbasdf correct, I'm trying to get theactive
attribute (every entity in my data model has a commonactive
attribute) for theNSManagedObject
.
– andrewbuilder
Nov 13 '18 at 10:41
1
I think yourentityActive
should not be static: it's a property ofManaged
objects, not theManaged
class. YourwillDisplayCell
code therefore needs to identify whichManaged
object is required - presumably using theindexPath
to look up in the datasource.
– pbasdf
Nov 13 '18 at 10:55
|
show 1 more comment
The Problem
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]:
this class is not key value coding-compliant for the key active.'
Thanks to @GrahamPerks answer to this SO question, I inserted an exception breakpoint in my code, which now pauses execution at this line...
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool // <-- PAUSES AT THIS LINE
This obviously needs further explanation...
Background
I'm writing a Core Data app that uses a generic table view data source and delegate, more or less set up per Florian Kugler's book "Core Data", published in 2017 by objc.io.
I have successfully linked three separate UITableViewController
s to this generic data source / delegate. I am using a single main storyboard and these three controllers are linked to three UISplitViewController
master/detail views.
I have deleted the automatically generated dataSource and delegate connections within the storyboard UITableView
s (although whether I leave or remove these connections, seems to make no difference).
If I comment out the code for the static var entityActive
above, the project will successfully Build and Run.
My code uses the UITableViewDelegate
method tableView(_, willDisplay:, forRowAt:)
to change the .textColor
of text and .backgroundColor
of cells, based on an attribute "active", stored as a boolean Scalar Type value with each entity.
For clarity, I'm trying to get the "active" attribute (every entity in my data model has a common attribute "active") for each NSManagedObject
for the entity. The value of that "active" attribute (Bool
true
or false
) for each entity is then used to format the cell in the if...else statement in the following code.
To attempt to maximise code reuse and minimise code repetition, I have also placed this delegate method in my generic data source / delegate class.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let entityObjectActive = T.entityActive
if entityObjectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
The compiler doesn't complain.
I seem to be able to use the generic type T
(representing Core Data entities) to associate the static property entityActive
with my instance of entityObjectActive
- so this seems to work...
let entityObjectActive = T.entityActive
To confirm, I have the following:
generic data source class....
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
protocol...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
static var entityActive: Bool get
}
and extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool
Attempts at Problem Solving
I've done some reading attempting to resolve my problem, including a review of many blogs (on how to set up generics in general and generic table view data sources) and a lot of SO Q&A, in particular...
How to fix Error: this class is not key value coding-compliant for the key tableView.'
Uncaught exception: This class is not key value coding-compliant
setValue:forUndefinedKey: this class is not key value coding-compliant for the key
It seems that all the SO Q&A are directly related to an issue with IB connections within storyboards. Maybe this is my issue too - but if that is the case it seems to me to be very well hidden.
Any assistance or advice please?
PS: I'm learning Swift after being a long time coder in Obj-C and I'm really struggling with the Generics Protocols Extensions paradigm shift, so it could be that my use of generic types is incorrect?
ios swift uitableview generics core-data
The Problem
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]:
this class is not key value coding-compliant for the key active.'
Thanks to @GrahamPerks answer to this SO question, I inserted an exception breakpoint in my code, which now pauses execution at this line...
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool // <-- PAUSES AT THIS LINE
This obviously needs further explanation...
Background
I'm writing a Core Data app that uses a generic table view data source and delegate, more or less set up per Florian Kugler's book "Core Data", published in 2017 by objc.io.
I have successfully linked three separate UITableViewController
s to this generic data source / delegate. I am using a single main storyboard and these three controllers are linked to three UISplitViewController
master/detail views.
I have deleted the automatically generated dataSource and delegate connections within the storyboard UITableView
s (although whether I leave or remove these connections, seems to make no difference).
If I comment out the code for the static var entityActive
above, the project will successfully Build and Run.
My code uses the UITableViewDelegate
method tableView(_, willDisplay:, forRowAt:)
to change the .textColor
of text and .backgroundColor
of cells, based on an attribute "active", stored as a boolean Scalar Type value with each entity.
For clarity, I'm trying to get the "active" attribute (every entity in my data model has a common attribute "active") for each NSManagedObject
for the entity. The value of that "active" attribute (Bool
true
or false
) for each entity is then used to format the cell in the if...else statement in the following code.
To attempt to maximise code reuse and minimise code repetition, I have also placed this delegate method in my generic data source / delegate class.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let entityObjectActive = T.entityActive
if entityObjectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
The compiler doesn't complain.
I seem to be able to use the generic type T
(representing Core Data entities) to associate the static property entityActive
with my instance of entityObjectActive
- so this seems to work...
let entityObjectActive = T.entityActive
To confirm, I have the following:
generic data source class....
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
protocol...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
static var entityActive: Bool get
}
and extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
static var entityActive: Bool
return entity.value(forKey: "active") as! Bool
Attempts at Problem Solving
I've done some reading attempting to resolve my problem, including a review of many blogs (on how to set up generics in general and generic table view data sources) and a lot of SO Q&A, in particular...
How to fix Error: this class is not key value coding-compliant for the key tableView.'
Uncaught exception: This class is not key value coding-compliant
setValue:forUndefinedKey: this class is not key value coding-compliant for the key
It seems that all the SO Q&A are directly related to an issue with IB connections within storyboards. Maybe this is my issue too - but if that is the case it seems to me to be very well hidden.
Any assistance or advice please?
PS: I'm learning Swift after being a long time coder in Obj-C and I'm really struggling with the Generics Protocols Extensions paradigm shift, so it could be that my use of generic types is incorrect?
ios swift uitableview generics core-data
ios swift uitableview generics core-data
edited Nov 13 '18 at 10:56
andrewbuilder
asked Nov 12 '18 at 23:50
andrewbuilderandrewbuilder
2,2181633
2,2181633
1
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed asManaged.entity
when it's static?
– Joakim Danielson
Nov 13 '18 at 6:33
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
1
Per your extension,entity
is anNSEntityDescription
: there's noactive
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get theactive
attribute for the NSManagedObject?
– pbasdf
Nov 13 '18 at 10:39
@pbasdf correct, I'm trying to get theactive
attribute (every entity in my data model has a commonactive
attribute) for theNSManagedObject
.
– andrewbuilder
Nov 13 '18 at 10:41
1
I think yourentityActive
should not be static: it's a property ofManaged
objects, not theManaged
class. YourwillDisplayCell
code therefore needs to identify whichManaged
object is required - presumably using theindexPath
to look up in the datasource.
– pbasdf
Nov 13 '18 at 10:55
|
show 1 more comment
1
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed asManaged.entity
when it's static?
– Joakim Danielson
Nov 13 '18 at 6:33
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
1
Per your extension,entity
is anNSEntityDescription
: there's noactive
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get theactive
attribute for the NSManagedObject?
– pbasdf
Nov 13 '18 at 10:39
@pbasdf correct, I'm trying to get theactive
attribute (every entity in my data model has a commonactive
attribute) for theNSManagedObject
.
– andrewbuilder
Nov 13 '18 at 10:41
1
I think yourentityActive
should not be static: it's a property ofManaged
objects, not theManaged
class. YourwillDisplayCell
code therefore needs to identify whichManaged
object is required - presumably using theindexPath
to look up in the datasource.
– pbasdf
Nov 13 '18 at 10:55
1
1
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed as
Managed.entity
when it's static?– Joakim Danielson
Nov 13 '18 at 6:33
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed as
Managed.entity
when it's static?– Joakim Danielson
Nov 13 '18 at 6:33
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
1
1
Per your extension,
entity
is an NSEntityDescription
: there's no active
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get the active
attribute for the NSManagedObject?– pbasdf
Nov 13 '18 at 10:39
Per your extension,
entity
is an NSEntityDescription
: there's no active
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get the active
attribute for the NSManagedObject?– pbasdf
Nov 13 '18 at 10:39
@pbasdf correct, I'm trying to get the
active
attribute (every entity in my data model has a common active
attribute) for the NSManagedObject
.– andrewbuilder
Nov 13 '18 at 10:41
@pbasdf correct, I'm trying to get the
active
attribute (every entity in my data model has a common active
attribute) for the NSManagedObject
.– andrewbuilder
Nov 13 '18 at 10:41
1
1
I think your
entityActive
should not be static: it's a property of Managed
objects, not the Managed
class. Your willDisplayCell
code therefore needs to identify which Managed
object is required - presumably using the indexPath
to look up in the datasource.– pbasdf
Nov 13 '18 at 10:55
I think your
entityActive
should not be static: it's a property of Managed
objects, not the Managed
class. Your willDisplayCell
code therefore needs to identify which Managed
object is required - presumably using the indexPath
to look up in the datasource.– pbasdf
Nov 13 '18 at 10:55
|
show 1 more comment
1 Answer
1
active
oldest
votes
Thanks to those whose comments pointed me towards this solution...
My REVISED protocol Managed
...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
var attributeActive: Bool get // <-- REMOVED static
My REVISED extension of Managed
...
UPDATE - added var attributeActive
to Managed
extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
var attributeActive: Bool
guard let attribute = self.value(forKey: "active") as? Bool else
return false // in case key "active" is not set
return attribute
UPDATE - deleted var attributeActive
from managed object extensions as no longer required...
My REVISED extensions for each of my three Core Data Entities (the data of which is displayed in each of the three separate UITableViewController
s)...
extension <<DataModelEntity>>: Managed
public var attributeActive: Bool
return self.active
@NSManaged public var active: Bool
@NSManaged public var <<OTHER DATA MODEL ENTITY ATTRIBUTES>> //...
// ...etc.
Maybe it is worth noting here for clarity that the Codegen value for each entity in the data model is set to Manual/None, so I have manually1 prepared classes and extensions for each entity.
1 When I write manually, I mean that I used the Create Managed Object Subclass... function under the Editor menu in Xcode and then manually entered my Managed
protocol stubs.
Finally, my REVISED generic data source delegate class...
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let object = fetchedResultsController.object(at: indexPath)
let objectActive = object.attributeActive
if objectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
// lots more code...
If anyone is still reading this essay, maybe you're interested in the reasons for this solution?
Frankly I'm still figuring out the details myself and plan to add a more concise / accurate reason in the future as my understanding improves regarding swift generics, protocols and extensions, but for now I provide the following...
As pointed out in comments, I was incorrectly attempting to get an entity property based on a data model attribute from an entity description. This is like trying to get the colour or size of a Lego brick by asking the Lego box for the characteristics of one of it's bricks. "Which brick?" might the box ask, if Lego boxes could ask such a thing.
Essentially I made a couple of errors. I didn't understand the effect the static definition had on my variables and I didn't properly understand how my Managed
protocol and extension interacted with any classes that adopted that protocol.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271766%2fswift-generic-table-view-data-source-and-delegate-protocol-backed-nsmanagedobje%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks to those whose comments pointed me towards this solution...
My REVISED protocol Managed
...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
var attributeActive: Bool get // <-- REMOVED static
My REVISED extension of Managed
...
UPDATE - added var attributeActive
to Managed
extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
var attributeActive: Bool
guard let attribute = self.value(forKey: "active") as? Bool else
return false // in case key "active" is not set
return attribute
UPDATE - deleted var attributeActive
from managed object extensions as no longer required...
My REVISED extensions for each of my three Core Data Entities (the data of which is displayed in each of the three separate UITableViewController
s)...
extension <<DataModelEntity>>: Managed
public var attributeActive: Bool
return self.active
@NSManaged public var active: Bool
@NSManaged public var <<OTHER DATA MODEL ENTITY ATTRIBUTES>> //...
// ...etc.
Maybe it is worth noting here for clarity that the Codegen value for each entity in the data model is set to Manual/None, so I have manually1 prepared classes and extensions for each entity.
1 When I write manually, I mean that I used the Create Managed Object Subclass... function under the Editor menu in Xcode and then manually entered my Managed
protocol stubs.
Finally, my REVISED generic data source delegate class...
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let object = fetchedResultsController.object(at: indexPath)
let objectActive = object.attributeActive
if objectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
// lots more code...
If anyone is still reading this essay, maybe you're interested in the reasons for this solution?
Frankly I'm still figuring out the details myself and plan to add a more concise / accurate reason in the future as my understanding improves regarding swift generics, protocols and extensions, but for now I provide the following...
As pointed out in comments, I was incorrectly attempting to get an entity property based on a data model attribute from an entity description. This is like trying to get the colour or size of a Lego brick by asking the Lego box for the characteristics of one of it's bricks. "Which brick?" might the box ask, if Lego boxes could ask such a thing.
Essentially I made a couple of errors. I didn't understand the effect the static definition had on my variables and I didn't properly understand how my Managed
protocol and extension interacted with any classes that adopted that protocol.
add a comment |
Thanks to those whose comments pointed me towards this solution...
My REVISED protocol Managed
...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
var attributeActive: Bool get // <-- REMOVED static
My REVISED extension of Managed
...
UPDATE - added var attributeActive
to Managed
extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
var attributeActive: Bool
guard let attribute = self.value(forKey: "active") as? Bool else
return false // in case key "active" is not set
return attribute
UPDATE - deleted var attributeActive
from managed object extensions as no longer required...
My REVISED extensions for each of my three Core Data Entities (the data of which is displayed in each of the three separate UITableViewController
s)...
extension <<DataModelEntity>>: Managed
public var attributeActive: Bool
return self.active
@NSManaged public var active: Bool
@NSManaged public var <<OTHER DATA MODEL ENTITY ATTRIBUTES>> //...
// ...etc.
Maybe it is worth noting here for clarity that the Codegen value for each entity in the data model is set to Manual/None, so I have manually1 prepared classes and extensions for each entity.
1 When I write manually, I mean that I used the Create Managed Object Subclass... function under the Editor menu in Xcode and then manually entered my Managed
protocol stubs.
Finally, my REVISED generic data source delegate class...
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let object = fetchedResultsController.object(at: indexPath)
let objectActive = object.attributeActive
if objectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
// lots more code...
If anyone is still reading this essay, maybe you're interested in the reasons for this solution?
Frankly I'm still figuring out the details myself and plan to add a more concise / accurate reason in the future as my understanding improves regarding swift generics, protocols and extensions, but for now I provide the following...
As pointed out in comments, I was incorrectly attempting to get an entity property based on a data model attribute from an entity description. This is like trying to get the colour or size of a Lego brick by asking the Lego box for the characteristics of one of it's bricks. "Which brick?" might the box ask, if Lego boxes could ask such a thing.
Essentially I made a couple of errors. I didn't understand the effect the static definition had on my variables and I didn't properly understand how my Managed
protocol and extension interacted with any classes that adopted that protocol.
add a comment |
Thanks to those whose comments pointed me towards this solution...
My REVISED protocol Managed
...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
var attributeActive: Bool get // <-- REMOVED static
My REVISED extension of Managed
...
UPDATE - added var attributeActive
to Managed
extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
var attributeActive: Bool
guard let attribute = self.value(forKey: "active") as? Bool else
return false // in case key "active" is not set
return attribute
UPDATE - deleted var attributeActive
from managed object extensions as no longer required...
My REVISED extensions for each of my three Core Data Entities (the data of which is displayed in each of the three separate UITableViewController
s)...
extension <<DataModelEntity>>: Managed
public var attributeActive: Bool
return self.active
@NSManaged public var active: Bool
@NSManaged public var <<OTHER DATA MODEL ENTITY ATTRIBUTES>> //...
// ...etc.
Maybe it is worth noting here for clarity that the Codegen value for each entity in the data model is set to Manual/None, so I have manually1 prepared classes and extensions for each entity.
1 When I write manually, I mean that I used the Create Managed Object Subclass... function under the Editor menu in Xcode and then manually entered my Managed
protocol stubs.
Finally, my REVISED generic data source delegate class...
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let object = fetchedResultsController.object(at: indexPath)
let objectActive = object.attributeActive
if objectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
// lots more code...
If anyone is still reading this essay, maybe you're interested in the reasons for this solution?
Frankly I'm still figuring out the details myself and plan to add a more concise / accurate reason in the future as my understanding improves regarding swift generics, protocols and extensions, but for now I provide the following...
As pointed out in comments, I was incorrectly attempting to get an entity property based on a data model attribute from an entity description. This is like trying to get the colour or size of a Lego brick by asking the Lego box for the characteristics of one of it's bricks. "Which brick?" might the box ask, if Lego boxes could ask such a thing.
Essentially I made a couple of errors. I didn't understand the effect the static definition had on my variables and I didn't properly understand how my Managed
protocol and extension interacted with any classes that adopted that protocol.
Thanks to those whose comments pointed me towards this solution...
My REVISED protocol Managed
...
protocol Managed: class, NSFetchRequestResult
static var entity: NSEntityDescription get
var attributeActive: Bool get // <-- REMOVED static
My REVISED extension of Managed
...
UPDATE - added var attributeActive
to Managed
extension...
extension Managed where Self: NSManagedObject
static var entity: NSEntityDescription return entity()
var attributeActive: Bool
guard let attribute = self.value(forKey: "active") as? Bool else
return false // in case key "active" is not set
return attribute
UPDATE - deleted var attributeActive
from managed object extensions as no longer required...
My REVISED extensions for each of my three Core Data Entities (the data of which is displayed in each of the three separate UITableViewController
s)...
extension <<DataModelEntity>>: Managed
public var attributeActive: Bool
return self.active
@NSManaged public var active: Bool
@NSManaged public var <<OTHER DATA MODEL ENTITY ATTRIBUTES>> //...
// ...etc.
Maybe it is worth noting here for clarity that the Codegen value for each entity in the data model is set to Manual/None, so I have manually1 prepared classes and extensions for each entity.
1 When I write manually, I mean that I used the Create Managed Object Subclass... function under the Editor menu in Xcode and then manually entered my Managed
protocol stubs.
Finally, my REVISED generic data source delegate class...
class MyDataSource<T: Managed,
Delegate: TableViewDataSourceDelegate>:
NSObject,
UITableViewDataSource,
UITableViewDelegate,
NSFetchedResultsControllerDelegate
// lots of code...
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
let object = fetchedResultsController.object(at: indexPath)
let objectActive = object.attributeActive
if objectActive == true
cell.textLabel?.textColor = UIColor.black
cell.detailTextLabel?.textColor = UIColor.darkGray
cell.backgroundColor = UIColor.white
else if entityObjectActive == false
cell.textLabel?.textColor = UIColor.lightGray
cell.detailTextLabel?.textColor = UIColor.lightGray
cell.backgroundColor = UIColor.clear
// lots more code...
If anyone is still reading this essay, maybe you're interested in the reasons for this solution?
Frankly I'm still figuring out the details myself and plan to add a more concise / accurate reason in the future as my understanding improves regarding swift generics, protocols and extensions, but for now I provide the following...
As pointed out in comments, I was incorrectly attempting to get an entity property based on a data model attribute from an entity description. This is like trying to get the colour or size of a Lego brick by asking the Lego box for the characteristics of one of it's bricks. "Which brick?" might the box ask, if Lego boxes could ask such a thing.
Essentially I made a couple of errors. I didn't understand the effect the static definition had on my variables and I didn't properly understand how my Managed
protocol and extension interacted with any classes that adopted that protocol.
edited Nov 14 '18 at 22:00
answered Nov 14 '18 at 7:24
andrewbuilderandrewbuilder
2,2181633
2,2181633
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271766%2fswift-generic-table-view-data-source-and-delegate-protocol-backed-nsmanagedobje%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Are you sure you can access a static variable using key-value coding? Shouldn't it be accessed as
Managed.entity
when it's static?– Joakim Danielson
Nov 13 '18 at 6:33
@JoakimDanielson thanks for your question but honestly I'm not sure, I'm new to Swift and generics, self taught on Obj-C and always preferred blocks to protocols in Obj-C, so part of my problem may be a general and basic lack of understanding of static variables, protocols and KVC. (PS tried your suggestion but could not make it work.)
– andrewbuilder
Nov 13 '18 at 9:53
1
Per your extension,
entity
is anNSEntityDescription
: there's noactive
property for NSEntityDescriptions which is why you get the error. Do you in fact mean to get theactive
attribute for the NSManagedObject?– pbasdf
Nov 13 '18 at 10:39
@pbasdf correct, I'm trying to get the
active
attribute (every entity in my data model has a commonactive
attribute) for theNSManagedObject
.– andrewbuilder
Nov 13 '18 at 10:41
1
I think your
entityActive
should not be static: it's a property ofManaged
objects, not theManaged
class. YourwillDisplayCell
code therefore needs to identify whichManaged
object is required - presumably using theindexPath
to look up in the datasource.– pbasdf
Nov 13 '18 at 10:55