I am experimenting with Protocols and Delegates and I am stuck while initializing the delegate.
At the top my of my class, I tried adding
protocol myDelegateProtocol {
func clickedCellIndexPath(indexPath: Int)
}
class MyClass {
var myDelegate : myDelegateProtocol
override init() {
super.init()
self.setup() // error 1
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) // error 2
}
}
It started giving errors for both init closures
Both errors:
Property 'self.myDelegate' not initialized at super.init
What am I missing or doing wrong?
If I try declaring it as var myDelegate: myDelegateProtocol?
, it doesn't give that error, but it forces me to force unwrap myDelegate!
and it returns nil at this point.
Edit: If I force it unwrap at the top, then I receive error in the following parts..
...
var myDelegate : myDelegateProtocol!
func handleTap(sender: UITapGestureRecognizer? = nil) {
if let point = sender?.locationInView(collectionView) {
print("Y")
let clickedCell = collectionView!.indexPathForItemAtPoint(point)!.row
print(clickedCell) // prints
self.myDelegate.clickedCellIndexPath(clickedCell) // error here
}
}
Edit 2:
So my complete code..:
protocol myDelegateProtocol {
func clickedCellIndexPath(indexPath: Int)
}
class MyClass {
var myDelegate: KDRearrangableClickedCellDelegate!
override init() {
super.init()
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setup() {
if let collectionView = self.collectionView {
let tap = UITapGestureRecognizer(target: self, action: #selector(KDRearrangeableCollectionViewFlowLayout.handleTap(_:)))
tap.delegate = self
collectionView.addGestureRecognizer(tap)
}
}
func handleTap(sender: UITapGestureRecognizer? = nil) {
if let point = sender?.locationInView(collectionView) {
let clickedCell = collectionView!.indexPathForItemAtPoint(point)!.row
print(clickedCell)
self.myDelegate.clickedCellIndexPath(clickedCell)
}
}
And I receive this error at this point:
fatal error: unexpectedly found nil while unwrapping an Optional value
As others have pointed out, because myDelegate
is not initialized in init
, you must make it optional. For example:
var myDelegate: KDRearrangableClickedCellDelegate?
Then when you need to use it, unwrap this optional, e.g.:
func handleTap(sender: UITapGestureRecognizer) {
if let point = sender.locationInView(collectionView) {
if let clickedCell = collectionView?.indexPathForItemAtPoint(point)?.item {
print(clickedCell)
myDelegate?.clickedCellIndexPath(clickedCell)
}
}
}
Personally, I'd recommend the use of an optional (KDRearrangableClickedCellDelegate?
) rather than an implicitly unwrapped one (KDRearrangableClickedCellDelegate!
), so that if you haven't yet set myDelegate
, your app won't crash. Clearly, if you want clickedCellIndexPath
to be called, you have to actually set myDelegate
. I'm also doing optional binding of the clickedCell
, so that if the tap wasn't on a cell, it won't crash. Also, I'm using item
rather than row
, as collection views generally don't use item
/section
rather than row
/section
.
You don't show us how you set collectionView
nor how you set myDelegate
, but for the above to work, you need to set both of those before the gestures can be handled correctly.
As an aside, I don't know what the relationship is between MyClass
and its myDelegate
, but often you make delegates weak
to avoid strong reference cycles. To do that, define your protocol as a class protocol:
protocol myDelegateProtocol : class {
func clickedCellIndexPath(indexPath: Int)
}
And then define your myDelegate
to be weak
:
weak var myDelegate: KDRearrangableClickedCellDelegate?
You only need to do this is if the object that will be the myDelegate
for MyClass
will, itself, maintain a strong reference to MyClass
. If not, you may not need to make your delegate weak. It just depends upon your object model, which you haven't shared with us.