Swift NSSet & CoreData

I am trying to move a C and CoreData object application to Swift and iOS and hit a brick wall using iteration through NSSet objects:

Xcode created these classes:

class Response: NSManagedObject { @NSManaged var responseText: String @NSManaged var score: NSNumber @NSManaged var answers: NSSet @NSManaged var question: Question } class Question: NSManagedObject { @NSManaged var questionText: String @NSManaged var questionType: String @NSManaged var qualifier: Qualifier @NSManaged var responses: NSSet } 

then in the 3rd grade I add a method that needs to be iterated over, but NSSet ..

 class Answer: NSManagedObject { @NSManaged var evaluation: Evaluation @NSManaged var response: Response func scoreGap() -> Int { var max = 0 for aresponse in self.response.question.responses { // this next line throws an error var scoreVal = aresponse.score.integerValue if scoreVal > max { max = scoreVal } } return max - self.response.score.integerValue } } 

The line after the comment above gives the error "AnyObject does not have a member named score"

The Objective-C method looks and works just fine:

 // returns the gap between the score of this answer and the max score -(NSNumber *)scoreGap { long max = 0; for(Response *aresponse in self.response.question.responses) { if(aresponse.score.longValue > max) max = aresponse.score.longValue; } max = max - self.response.score.longValue; return @(max); } 

It's about the third day in Swift, so I probably don't see anything obvious at all ... but at the moment I really don't understand it!

+5
source share
2 answers
 for aresponse in self.response.question.responses { // this next line throws an error var scoreVal = aresponse.score.integerValue 

The problem is that for aresponse in ... responses iterate through NSSet. Swift does not know what is in the NSSet, so it treats each aresponse value as an AnyObject that has no properties. Thus, the compiler complains when you try to get the score aresponse property.

On the other hand, you know that each aresponse value is an answer. So you need to say Swift, by casting (with as ). Note that you really did this in Objective-C code:

 for(Response *aresponse in self.response.question.responses) 

But you forgot to do the same in Swift. You can do this in many ways; for example, you could write a thing like this:

 for aresponse in self.response.question.responses { var scoreVal = (aresponse as Response).score.integerValue 

This forces us to bypass the compiler, which now shares our knowledge that this variable really is.

As soon as you get used to it, you will kiss the ground, which includes Swift. All this time, in Objective-C, you made assumptions about what kind of object you had, but actually what you had was id , and the compiler allowed you to send any message at all - and so, you often crashing with an "unrecognized selector". In Swift, an “unrecognized selector” failure is basically impossible, because the type of everything is set, and the compiler does not allow sending an unwanted message to an object in the first place.

+11
source

In fact, I found something useful. Starting with Xcode 7.2 and Swift 2.0, the following declaration works:

 @NSManaged var responses: Set<Response> 

I think this may be due to the fact that Swift automatically connects between NSSet and NSArray. I did not find this documented, but it works for me, and I would appreciate it if someone confirms it.

+3
source

Source: https://habr.com/ru/post/1207536/


All Articles