Error using subscript of optional array - swift

When using this code:
let result: AnyObject! = hitResults[0]
I am getting the following error:
[AnyObject]? does not have a member named subscript
Containing function for context:
func handleTap(gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as SCNView
// check what nodes are tapped
let p = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(p, options: nil)
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
let result: AnyObject! = hitResults[0]
// get its material
let material = result.node!.geometry?.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
// on completion - unhighlight
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
material?.emission.contents = UIColor.blackColor()
SCNTransaction.commit()
}
material?.emission.contents = UIColor.redColor()
SCNTransaction.commit()
}
}
Does anyone know what the issue here is?

This happens because hitTest returns an optional array, so you need to unwrap before using it.
Instead of checking that the hitResults has a count > 0, you could check that there the first object exists, and then proceed to using that object
if let firstHit = scnView.hitTest(p, options: nil)?.first {
// safely use firstHit here...
}

You can't use a subscript on an optional array. [AnyObject]? Is an optional array of type AnyObject. If you are sure that hitResults is non-nil, you can unwrap it with ! then use a subscript.
let result: AnyObject! = hitResults![0]

Since hitResults is an [AnyObject]?, you can't call subscript on it without unwrapping it first. The safest way to do this is using optional binding, like so:
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
if let result: AnyObject = hitResults?[0] {
/* safely use result here */
}
}
Or, even better, you can use optional binding with the first property of Array which returns the first element in the array if the Array is not empty, or nil:
// check that we clicked on at least one object and retrieve it
if let result = hitResults?.first {
/* safely use result here */
}

Related

Core Data - Change NSManagedObject array into array of Strings using valueForKey -OSX

So iv using an NSTokenField to allow data entry, the TokenField will suggest thing when the user starts typing. I want it to suggest things that are already inside core data.
To do this i have this function being called when the cell moves to superview (This is all happening inside a custom table view cell)
var subjectInformation = [NSManagedObject]()
let appDel = NSApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "SubjectInformation")
do {
let results = try context.executeFetchRequest(fetchRequest)
subjectInformation = results as! [NSManagedObject]
} catch {
}
this returns an array of NSManagedObjects, now i want for every object in managed object get get the valueForKey("subjectName") as insert it into a array of string so that i can return that inside this token field Function
func tokenField(tokenField: NSTokenField, completionsForSubstring substring: String, indexOfToken tokenIndex: Int, indexOfSelectedItem selectedIndex: UnsafeMutablePointer<Int>) -> [AnyObject]? {
return subjectInformation //this is where is should return an array eg; ["English","Maths","Science"]
How would i do this? Thanks :)
If you properly subclassed your NSManagedObject you can use expressive Swift style filters and maps. You would cast your results array to [SubjectInformation] and
let subjectList = subjectInformation.map { $0.subjectName }
Try this:
(subjectInformation as! NSArray).valueForKeyPath("#unionOfObjects.subjectName")
This should return an array of the subjectNames of all the subjectInformation items.

Swift2: return a optional type object

I'm new in the swift2 world and I currently struggle with a simple function :
// Get all moves for the first category
func getMuscles() -> BodyPart {
let bpart:BodyPart?
if let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext {
do{
let fetchRequest = NSFetchRequest(entityName: "BodyPart")
let fetchResults = try managedObjectContext.executeFetchRequest(fetchRequest) as! [BodyPart]
bpart = fetchResults[0]
} catch let error as NSError {
print(error)
bpart = nil
}
}
return bpart
}
How can I solve this issue ? And what are the 'best-practices' in swift2 for defining a function ?
Thank you
EDIT 1
I've tried to change the signature of the method, but error is still here :
The question you should be asking yourself is whether getMuscles() must always return an object or if it's fine for it to return a nil.
By changing the method signature to func getMuscles() -> BodyPart?,
you're basically stating that a nil might be returned from that method,
thus solving your immediate compile time issue.
In that particular context, because you're fetching objects from CoreData,
it might be wise to allow getMuscles() to return a nil.
The way you define your functions (if they return optionals ?, or not) entirely depends on the calling code.
Change your method signature to :
func getMuscles() -> BodyPart?
But be careful while unwrapping the return value when the this function is being called.
Just return:
func getMuscles() -> BodyPart? { }
Thats nothing to do with SWIFT2.. The return type is expecting some value BodyPart not an optional value BodyPart?...But you are returning a optional value bpart
func getMuscles() -> BodyPart {
let bpart:BodyPart?
....
return bpart
}
If you want to return bpart as it is you need to create the return type as optional
func getMuscles() -> BodyPart? {
let bpart:BodyPart?
....
return bpart
}
or if you want to just return the value try this
func getMuscles() -> BodyPart {
let bpart:BodyPart = ()//initialize here dont make optional
....
return bpart
}

Swift - how to make inner property optional

My question is in regards to optionals in swift. Let say i have the following defined already:
if let myCell = cell as? AECell {
if !myCell.someView.hidden{
//how do i use optional on someView, perhaps someView will not exists
}
}
as you can see, what if someView is nil , how do i use an optional here to only execute the if statement if someView is not nil ..i tried the question mark:
if !myCell.someView?.hidden but its syntax is not correct
if let myCell = cell as? AECell, let someView = myCell.someView {
// someView is unwrapped now
}
This should do it:
if let myCell = cell as? AECell, let myView = myCell.someView where !myView.hidden {
// This gets executed only if:
// - cell is downcast-able to AECell (-> myCell)
// - myCell.myView != nil (-> unwrapped)
// - myView.hidden == false
}
You could use optional chaining
if let myView = (cell as? AECell).someView {
if !myView.hidden{
// do something
}
}
To answer the question directly, yes you can use optionals this way. The someView property of your cell must be defined as optional.
class MyCell: UICollectionViewCell {
var someView: AECell?
}
Then you can use the following syntax:
myCell.someView?.hidden = true
The behavior you're talking about is very much akin to Objective-C's nil messaging behavior. In Swift,you want to lean more towards confirming the existence of an object before manipulating it.
guard let myView = myCell.someView as? AECell else {
// View is nil, deal with it however you need to.
return
}
myView.hidden = false

Getting an error while loading data into WKInterfaceTable

I create a watchKit app/extension of my app. I use this func to load the data into the WKInterfaceTable:
// Load table into the data
func loadTableData() {
let sharedDefault = NSUserDefaults(suiteName: "group.com.Devpr.App")
let numberItems = sharedDefault?.objectForKey("numberItems") as? Int
tableView.setNumberOfRows(numberItems!, withRowType: "Cell")
var i = 0
let task = sharedDefault?.objectForKey("\(i)WK") as? String
let row = tableView.rowControllerAtIndex(i) as! TableRowObject // Get a single row object for the current item
row.lblTblRowItem.setText(task) // Set the row text to the corresponding item
i++ // Move onto the next item
}
The app is crashing in this line of the function: let row = tableView.rowControllerAtIndex(i) as! TableRowObject with this error: fatal error: unexpectedly found nil while unwrapping an Optional value. I really can't find anything which is nil.
Image after the crash:
I hope someone of you can help me to solve this. Thanks a lot for you're help!
If numberOfItems is 0, tableView.rowControllerAtIndex(i) can be nil.

Type casting operator

In Swift guide that as published on ibooks, as! operator was not mentioned. But in online reference and in some example code, they (i mean Apple in both cases) used as! operator.
Is there a difference between as and as! operators? If there are, can you explain please?
edit: Im so tired that i wrongly typed "is", instead of "as". That is now corrected...
as? will do an optional downcast - meaning if it fails it will return nil
so "Blah" as? Int will return Int? and will be a nil value if it fails or an Int if it does not.
as! forces the downcast attempt and will throw an exception if the cast fails. Generally you will want to favour the as? downcast
//ex optional as?
let nine = "9"
if let attemptedNumber = nine as? Int {
println("It converted to an Int")
}
//ex as!
let notNumber = "foo"
let badAttempt = notNumber as! Int // crash!
( You may find that you that an update is sitting there for the swift guide. It is mentioned for sure in the online version https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html )
operator is the forcefully unwrapped optional form of the as? operator. As with any force unwrapping though, these risk runtime errors that will crash your app should the unwrapping not succeed.
Further, We should use as to upcast if you wish to not write the type on the left side, but it is probably best practice to write it with normal typing as shown above for upcasting.
Example:
You use the as keyword to cast data types. UIWindow rootViewController is of type UIViewController. You downcast it to UISplitViewController.
Another better example can be taken as follows.
var shouldBeButton: UIView = UIButton()
var myButton: UIButton = shouldBeButton as UIButton
The as? operator returns an optional, and then we use optional binding to assign it to a temporary constant, and then use that in the if condition, like we are doing in the below example.
let myControlArray = [UILabel(), UIButton(), UIDatePicker()]
for item in myControlArray
{
if let myLabel = item as? UILabel
{
var storeText = myLabel.text
}
else if let someDatePicker = item as? UIDatePicker
{
var storeDate = someDatePicker.date
}
}