5

I recently stumbled onto something weird in my code, I have programming in the same project for a few days but all of a sudden I tried to create a lazy property with this code:

import UIKit

class CategoryViewController: UICollectionViewController {

  lazy var searchController: UISearchController = {
    let searchController = UISearchController(searchResultsController: nil)
    searchController.searchBar.frame = CGRect(x: 0, y: 0, width: CGRectGetWidth(self.collectionView.frame), height: 44)
    return searchController
    }()
}

Now every time I try to reference self from with in the lazy block it produces this:

self.(<#NSObject#>)

and can't access none of the other properties.

If i try to hard-code them it produces:

UICollectionView? does not have a member named 'frame'

And the code above displays:

Extra argument 'width' in call

I already tried to rewrite the code and eliminating the derived data, build again but the error keeps persisting. Any ideas as to why it could happen?

Thanks in advance

Update autocomplete box:

enter image description here

Jake Ortiz
  • 503
  • 9
  • 20

1 Answers1

1

UICollectionView? does not have a member named 'frame'

See the question mark? That means this is an Optional. You cannot send any messages to an Optional until you unwrap it. So unwrap it: self.collectionView!.frame

EDIT The reason this worked before, and then your code broke, is that the Swift API changed. Apple does this a lot, so you have to "roll with the punches". You need to be ready for your code to break every time you upgrade Xcode. They have changed their minds three times about whether a UICollectionViewController's collectionView should be an Optional or not. And I am not at all convinced that their answer is correct even now.

Further edit Showing that autocompletion works:

enter image description here

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I think you can send messages to optionals, but you can't get their properties unless you unwrap it – Dániel Nagy Dec 16 '14 at 15:20
  • 1
    @DánielNagy What I mean is that you can only send Optional messages to Optionals (such as the special Optional `map`), and you'll never have a reason to do that. And an Optional has no properties. It's the thing wrapped inside it that has properties; that is why you have to unwrap it! – matt Dec 16 '14 at 15:22
  • 1
    @DánielNagy If you don't understand what an Optional is, see my answer here: http://stackoverflow.com/a/27370841/341994 – matt Dec 16 '14 at 15:24
  • well, I didn't know that. But what I meant is that for example you can send a message to an optional, like delegates and you don't have to unwrap the delegates. There could be some confusion on my side, I was just arguing with your statement: "You cannot send any messages to an Optional until you unwrap it." – Dániel Nagy Dec 16 '14 at 15:29
  • 1
    @DánielNagy Yes you do have to unwrap the delegate. If a delegate is typed as `MyDelegateType?`, that is an Optional and you cannot send a message to it until you unwrap it. – matt Dec 16 '14 at 15:30
  • You mean explicitly unwrap it? – Dániel Nagy Dec 16 '14 at 15:35
  • @DánielNagy I mean unwrap it. An Optional may be unwrapped implicitly or explicitly, but it must be unwrapped in order to send any message to the thing inside. That is what unwrapping _is_. – matt Dec 16 '14 at 15:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67028/discussion-between-daniel-nagy-and-matt). – Dániel Nagy Dec 16 '14 at 15:36
  • The problem is that it was possible before but all of a sudden it does not let me anymore – Jake Ortiz Dec 16 '14 at 15:41
  • @JakeOrtiz I understand! It is because you upgraded to 6.1.1 or 6.2. Yes, it changed. You must be ready for this sort of thing. The Swift language and API are always changing. – matt Dec 16 '14 at 15:43
  • I have 6.1.1 and have had it for a few days already, and yesterday I was able to do it. And other projects I have are also able to use this same code – Jake Ortiz Dec 16 '14 at 15:45
  • 1
    Probably just leftover caches. Clean out the caches as I explain here: http://stackoverflow.com/questions/5714372/how-to-empty-caches-and-clean-all-targets-xcode-4/6247073#6247073 Then all your code will break in exactly the same way. :) – matt Dec 16 '14 at 15:46
  • 1
    Ok as you predicted now it breaks my code, at least I understand why now. The only problem is that the self.(<#NSObject#>) keeps being there and autocompletes only allows that option no there properties can be found in autocomplete – Jake Ortiz Dec 16 '14 at 15:53
  • @JakeOrtiz I don't understand that part of your question, sorry. I do not know what "every time I try to reference self it produces this" means. What do you mean by "reference" and "produce"? Produces when? How? In a `println`? – matt Dec 16 '14 at 16:00
  • 1
    My bad, when I read it outlaid it sounded weird. When you type self. the autocomplete box appears usually with all the properties and methods that can be used by that class. But now the only option that autocompletes displays is the one with the nsobject. I'll attach an image in the original post – Jake Ortiz Dec 16 '14 at 18:32
  • The problem is that "self" is ambiguous. Instead of `self.`, type `let v = self.` and then do autocomplete. You can always take the `let v =` away again later. :) – matt Dec 16 '14 at 18:38