I'm trying to read data from firebase and draw rectangles according to the data in firebase. The colour will also fill accordingly to the value retrieved from the firebase. I have managed to retrieve the data from firebase and append them into arrays.
As Firebase is asynchronous, I have added completion handler to only run the following code after the readMarina() has completed. I am trying to test out the readMarina{} in draw() method by inputting a simple drawing of a rectangular box. Everything ran smoothly until the context?.fill(lot)
, where it gave an error of:
"Thread 1: EXC_BAD_ACCESS (code=1, address=0x7ffe00000058)"
override func draw(_ rect: CGRect)
{
let context = UIGraphicsGetCurrentContext()
let lot = CGRect(x: 80,y: 20,width: 30,height: 60)
readMarina{
context?.addRect(lot)
context?.setFillColor(UIColor.red.cgColor)
context?.fill(lot)
}
}
func readMarina (_ completion: (() -> Void)?){
let ref = Database.database().reference()
let cpDB = ref.child("CarPark")
cpDB.child("MarinaSq").observe(.value, with: {snapshot in
let snapshotValue = snapshot.value as! Dictionary<String, AnyObject>
for (key, value) in snapshotValue
{
if (self.lot.count)<((snapshotValue.count)){
let v = value as! String
let k = key
self.lot.append(k)
self.status.append(v)
}
}
completion?()
})
}
I tried to debug and when I hovered over "context" and "context?", they all showed a value. When I hovered over the "lot", there is also value parsed in. What is wrong with my code and why my rectangular box did not appear on my View?
As draw(_ rect: CGRect) function description says:
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay() or setNeedsDisplay(_:) method instead.
Your closure inside of draw(_ rect: CGRect) function is the one that makes interference in its execution process and most probably causes a crash. To handle this you should remove readMarina function call from inside of a draw(_ rect: CGRect). Here is a simple implementation:
class MyView: UIView {
var myColor: UIColor? {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
if let context = UIGraphicsGetCurrentContext(), let color = myColor {
let lot = CGRect(x: bounds.midX-50, y: bounds.midY-50, width: 100, height: 100)
context.addRect(lot)
context.setFillColor(color.cgColor)
context.fill(lot)
}
}
}
I added a View to my ViewController in Main.storyboard, and in identity inspector set custom class to "MyView".
class ViewController: UIViewController {
@IBOutlet weak var myView: MyView!
override func viewDidLoad() {
super.viewDidLoad()
testFunc {
self.myView.myColor = UIColor.red
}
}
func testFunc(completion:(() -> Void)?) {
// test func
completion?()
}
}