Unable to instantiate NSFetchedResultController with generic type AnyObject in Swift 3 - core-data

I'm experimenting with CoreData in Swift 3 and have come up against a very bizarre circular compiler error in Xcode 8 beta.
NSFetchedResultsController needs a generic type parameter and AnyObject has worked fine up until now. The compiler throws the error:
Type 'AnyObject' does not conform to protocol 'NSFetchRequestObject'
To make me extra confused, if you delete the type parameter, XCode then says:
Reference to generic type NSFetchedResultsController requires argument in `<...>`
and helpfully suggests a fix using <AnyObject>....and the cycle repeats.
This looks very much like a bug. Any ideas before I report it?

If you take a look into NSFetchedResultsController, you can clearly see that it has a parameter with name ResultType which conforms to NSFetchRequestResult. So you should pass a type which conforms to NSFetchRequestResult.
So if you take a look into NSFetchRequestResult, you can see that it conforms to NSObjectProtocol. Also NSDictionary, NSManagedObject and NSManagedObjectID conforms to NSFetchRequestResult.
public protocol NSFetchRequestResult : NSObjectProtocol {
}
extension NSDictionary : NSFetchRequestResult {
}
extension NSManagedObject : NSFetchRequestResult {
}
extension NSManagedObjectID : NSFetchRequestResult {
}
So it clear that you should pass a type from any of these three NSDictionary or NSManagedObject or NSManagedObjectID.
Create your instance of NSFetchedResultsController like this.
let resultsController : NSFetchedResultsController<NSManagedObject>!
or like this
let resultsController : NSFetchedResultsController<NSManagedObjectID>!
or like this
let resultsController : NSFetchedResultsController<NSDictionary>!

Any entity in your Core Data model maps as a subclass of NSManagedObject generated in your code so they all can be used to replace AnyObject, they all conform indirectly to NSFetchRequestResult protocol. You should see which entity/class is being fetch by your FetchRequest connected to this FetchedResultsController and that's the type you should use there.

Related

KVO notification with Core Data in Swift

When I generate an NSManagedObject subclass with swift, the property types are all #NSManaged, meaning I can't observe them. This is a problem when using bindings in a Cocoa application because updating the property frequently requires other properties to be 'updated'.
For example, if I add this method to my NSManagedObject subclass:
dynamic var ratePerPoint: Double {
guard pointsPerMonth > 0 else { return 0 }
return monthlyRate / Double(pointsPerMonth)
}
Then it's important that whenever I update the pointsPerMonth variable, which is part of the core data object, that I send a didChangeValueForKey("ratePerPoint") message.
If I don't, then the UI bindings don't update properly.
If ratePerPoint is a calculated property you have to implement keyPathsForValuesAffectingRatePerPoint in your NSManagedObject subclass.
+ (NSSet *)keyPathsForValuesAffectingRatePerPoint {
return [NSSet setWithObjects:#"monthlyRate", #"pointsPerMonth", nil];
}
Documentation: Registering Dependent Keys

unit-test tooltip visibility and content

Consider the following situation:
I got a title which is either 'A' when the type of an object is 'someType', or is empty apart from that. That is:
title="#{type eq 'someType' ? 'A' : ''}"
If the string returned by type changes, I won't get any errors. To be precise, the tooltip will be visible no longer, whilst I get no warnings on this. The important thing is, that type is not in my responsibility, but instead in another project. I defined an enum to use this in my code, which represents the values that type can receive.
public enum Type {
SOME_TYPE("someType"), //
ANOTHER_TYPE("anotherType");
String descr;
private Types(String descr) {
this.descr= descr;
}
}
Do you have any best practices here?

Ninject: Binding an interface with a generic that is also an interface

I have searched this issue but with no luck. Here we go.
Suppose I have an interface:
interface IQueryRepository<T> where T : class
and I want to bind any requests for:
IQueryRepository<IClient>
to:
ConcreteQueryRepository<Client>
I've tried the obvious:
Bind<IGenericQueryRepository<IClient>>().To<ConcreteQueryRepository<Client>>()
But I get an error:
ConcreteQueryRepository<Client> cannot be used as type parameter 'TImplementation' in
the generic type or method 'Ninject.Syntax.IBindingToSyntax<T>.To<TImplementation>()'
There is no implicit reference conversion from 'ConcreteQueryRepository<Client>'
to 'IGenericQueryRepository<IClient>'
But I don't understand why since GenericQueryRepository implements IGenericQueryRepository and Client implements IClient.
I would like Ninject to give me a concrete generic repository where T is Client. I want this to avoid using concrete types in the code.
Can it be done?
This has to do with Covariance and Contravariance.
In your question you mentioned the following:
... GenericQueryRepository implements IGenericQueryRepository and Client implements IClient.
Let's make it simpler by using fruits: Fruit implements IFruit. We'll also create a Tree class.
public interface IFruit { }
public class Fruit : IFruit { }
public class Tree<T> where T : IFruit { }
Tree<IFruit> tree = new Tree<Fruit>() // error
This will reproduce the same kind of error you're experiencing. Why? Simple.
Though Fruit implements IFruit, an Fruit Tree doesn't implement a IFruit Tree. There is no cast possible between the Fruit Tree and the IFruit Tree, although you would expect it. They are both Trees, but with a different type parameter. The fact that their type parameters are related to each other, doesn't matter.
In other words: there is no cast possible between the Fruit Tree and the IFruit Tree, because their type parameters don't match.
In general, when casting with generics, make sure their type parameters match. However, there are a few exceptional cases. See Variance in Generic Interfaces.
In your case, you could fix it by using IClient as type parameter for the GenericQueryRepository class. Doing this will allow casting because the type parameters match. But I don't know your application architecture, so this fix might be inapplicable in your case.
EDIT: To make it easier to understand, copy paste the code below and see what the compiler says.
interface IFruit { }
class Fruit : IFruit { }
interface ITree<T> where T : IFruit { }
class Tree<T> : ITree<T> where T : IFruit { }
class Program
{
static void Main(string[] args)
{
ITree<Fruit> test1 = new Tree<Fruit>(); // compiles: type parameters match
ITree<IFruit> test2 = new Tree<Fruit>(); // fails: type parameters don't match
ITree<Fruit> test3 = new Tree<IFruit>(); // fails: type parameters don't match
ITree<IFruit> test4 = new Tree<IFruit>(); // compiles: type parameters match
IEnumerable<IFruit> test5 = new List<Fruit>(); // compiles: this is one of the exceptional cases
}
}
That should clear things up about what is and what is not possible.
I've had the same problem when trying to bind a Dapper query to an interface type, thinking about it, it seems to make sense that Dapper can't instantiate an Interface type.
The interface is only a contract and does not know about how to instantiate a concrete implementation of it.
Dapper needs a type that is concrete implementation of the interface type otherwise Dapper would also have to know which concrete implementation of the interface to instantiate, and in that case Dapper would behave like a DI container which, indeed, it isn't.

Passing A Delegate In prepareForSegue Method

I am having a problem passing an object from a TableView to a ViewController in an IOS app. I am using storyboard and have elected ARC and passing the delegate in my "prepareForSegue" method.
Here is my code in my TableView which segues via a push to another ViewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NextViewController *vc = (NextViewController *)[segue destinationViewController];
vc.managedObjectContext = managedObjectContext;
if ([[segue identifier] isEqualToString:#"EditCategory"])
{
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
// I get a red warning which states "Cast of 'NSInteger' (aka 'int') to 'Entity' is disallowed with ARC" on this line:
[vc setEntity:(Entity *)selectedIndex];
}
}
Does anybody have any suggestions for how I can pass my object from the TableView to the ViewController? I am new to programming and have tried various expressions but nothing seems to work.
The error you're getting has to do with types.
The class NextViewController apparently has a method called -setEntity: that takes an object of type Entity *. The error is because you're trying to give -setEntity: an argument of the wrong type. You're trying to give it an NSInteger (which is a number like 0, 5, -999), but it wants an Entity.
You're on the right track for passing data from the table view to the NextViewController. You just need to do one of the following:
pass an Entity to -setEntity: (does the Entity class perhaps
have a constructor that takes an NSInteger?)
add a method to NextViewController that takes an NSInteger, and call that instead of -setEntity:

Unmarshalling to a subclass with JAXB

I've a JSON something like this:
objects:[{
id:"p452365",
type:"photo",
link:"http://xxx.zz"
},
{
id:"v7833",
type:"video",
link:"http://xxx.yy",
length:"4.12"
}
]
In superclass Entity, there're 2 instance variables: id and type. In my extended XmlAdapter class I tried to cast my Entity instances to a subtype for ex. Photo
public HashMap<String, List<Column>> unmarshal(Feeds f) throws Exception {
for(Feed feed : f.getFeeds()){
System.out.println("Entity id for feed : " + feed.getId());
for(Entity e:feed.getObjects()){
if (e instanceof Photo){
// Of course it's not
}
}
}
return (HashMap<String, List<Column>>)fm.map(f.getFeeds());
}
Of course e isn't an instanceof Photo, I took a shot there.:)
What I wanna do is to interfere the JAXB process sometime and unmarshall according to the type value in JSON.I wonder where and how.
One of my previous answers to a similar question may help here. Essentially it is using the #XmlDescrimatorNode in EclipseLink JAXB (MOXy). Note I'm the MOXy tech lead.
Java/JAXB: Unmarshall Xml to specific subclass based on an attribute
You could also do this with an XmlAdapter. AdaptedEntity would have all the properties from Entity and it's subclasses.
JAXB #XmlElements, different types but same name?

Resources