tapGesture change color [closed] - ios

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am trying to make a UIImageView named rDot tappable with tapGesture. When the image view rDot is tapped I want a different UIImageView on a different viewController, named wCircle to turn red. The problem is the code runs, but when I tap rDot the other image wCircle doesn't turn red.
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
rDot.isUserInteractionEnabled = true
rDot.addGestureRecognizer(tapGestureRecognizer)
}
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let wCircle = UIImageView(image: UIImage(named:"wCircle")?.withRenderingMode(.alwaysTemplate)) //error here
wCircle.tintColor = UIColor.red
}

In the context of Swift code, EXC_BAD_INSTRUCTION usually means you’ve hit a compiler trap, that is, an undefined instruction inserted into the code by the compiler because of a bug detected at runtime. The most common cause of these are:
failure to unwrap an optional — This can be a forced unwrap (!) or an implicit unwrap (accessing an implicitly unwrapped optional that’s nil).
array out of bounds
a failed forced cast (as!), either because the value was a nil optional or because the value was of the wrong type.
Check if wCircle is not nil.
Check if the outlet is properly connected.

make sure your image assets has an image exactly named "wCircle" case sensitive ,
again, in assets not in project bundle , i think UIImageView couldn't be initialized because an image with "wCircle" does not exist in assets

The way you init your UITapGestureRecognizer is incorrect.
Try
UITapGestureRecognizer(target: self, action: #selector(ViewController.imageTapped(tapGestureRecognizer:)))
Replace ViewController with your controller's class name

Make sure your object wCircle is present and initialize successfully

What is "wCircle" ? UIImage has no property called tintColor, if you want change image's color change his container UIImageView's tintColor

Related

Destination's View Controller variable becoming nil after being set

Basically there is something wrong either with my code, Swift or the compiler/Xcode itself. I have 2 ViewControllers and the second one (destination) has 2 UIImage variables. First ViewController sets those 2 images in prepareForSegue like this:
if let destVC = segue.destinationViewController as? SecondViewController {
destVC.firstImage = firstImage
destVC.secondImage = secondImage
}
Every time I checked what's going on in that part of code both firstImage and secondImage are set and are never nil (they are both created before that part of code, and I even logged to check it and they were never nil), however in viewDidLoad method in SecondViewController the app crashes cause firstImage is set, but secondImage is nil (and I force unwrapped it). I've tried compiling it numerous times - every time it's nil and it crashes. After that I've added print("hello world") line to the segue code, erased it, saved the file, compiled again and app never crashed again.
So my question here is - what exactly happened - judging by code, the secondImage should never be nil (since the secondImage is never nil, nor was it nil in debugger or when I make a breakpoint), so why did the secondImage in destVC became nil?
Also I need to mention that I'm using inbuilt Git, and I'm not sure if it's maybe somehow affecting or corrupting the files since I've already had issues where Xcode sometimes takes forever to reindex the code and autocompletion stops working for around 20-30 seconds until it does that (I have an iMac Retina with an i5 so this really shouldn't be an issue).
edit: let me add the code from SecondViewController to make things clear:
...
class SecondViewController: UIViewController {
...
var firstImage: UIImage?
var secondImage: UIImage?
...
override func viewDidLoad() {
super.viewDidLoad()
self.loadMainImage(self.firstImage!)
self.loadSecondaryImage(self.secondImage!) // secondImage was nil all the time here so it crashed at this point cause of force unwrap
...
}
...
}
So as you can see I'm setting everything properly, and the methods take UIImage(not optional UIImage?) and do something with those images, however secondImage was always nil. So my questions are - why is firstImage set normally, and second isn't? And why it started working normally when I added one line of code, then deleted it, and compiled everything again.
I'm aware that I can check if the secondImage is nil and that I can do optional unwrapping but the point here is - why did it get set to nil with no reason at all.
I was able to fix this by moving my code from viewDidLoad to viewWillAppear My class variables (set in the presenting view controller) were nil in viewDidLoad but were instantiated in the viewWillAppear The strange thing is that they worked in the viewDidLoad for a while. This seems to indicate a race condition, though I'm not sure that makes any sense.
You can pass image to another image property of the second VC and then set the "passed" image in the viewDidLoad of the SecondVC.
BUT you cannot pass or set the image directly to that of the imageView.image of the SecondVC, as secondVC.imageView is not yet allocated in memory.
What you need to do is create an UIImage Property in the .h of the secondVC and pass the image to that Image Property.
Set the image in the viewDidLoad

Why doesn't my View respond to a gesture using a gestureRecognizer?

Having just spent a day beating my head against the keyboard, I thought I'd share my diagnosis and solution.
Situation: You add a custom View of custom class CardView to an enclosing view myCards in your app and want each card to respond to a tap gesture (for example to indicate you want to discard the card). Typical code you start with:
In your ViewController:
class MyVC : UIViewController, UIGestureRecognizerDelegate {
...
func discardedCard(sender: UITapGestureRecognizer) {
let cv : CardView = sender.view! as! CardView
...
}
In your myCards construction:
cv = CardView(card: card)
myCards.addSubview(cv)
cv.userInteractionEnabled = true
...
let cvTap = UITapGestureRecognizer(target: self, action: Selector("discardedCard:"))
cvTap.delegate = self
cv.addGestureRecognizer(cvTap)
I found the arguments here very confusing and the documentation not at all helpful. It isn't clear that the target: argument refers to the class that implements discardedCard(sender: UITapGestureRecognizer) . If you're constructing the recognizer and cards in your ViewController that's going to be self. If you want to move the discardedCard into your custom View class (for example), then replace self with CardView in my example, including on the delegate line.
Testing the above code, I found that the discardedCard function was never called. What was going on?
So a day later, here's what I had to fix. I hope this checklist is useful to somebody else. I'm new to iOS (coming from Android), so it may be obvious to you veterans:
Make sure the touched view (cv in the example) has userInteractionEnabled=true . Note that if you use your own constructor it will be set false by default
Make sure all enclosing views also have userInteractionEnabled=true
Others have posted that the order of the delegate statement and addGestureRecognizer statement made a difference; I didn't find that using Xcode 7.2 and iOS 9.2
Most important: Make sure your touched view is fully within the bounds of the enclosing views. In my example, I was building a myCards container that didn't have the width set correctly and was cutting off the right-most cards (and since clipping is disabled by default, this wasn't visually obvious until I looked in the debugger at the View hierarchy)

passing parameters to a Selector in Swift

I am building an app for keeping track of reading assignments for a university course. Each ReadingAssignment has included a Bool value that indicates if the reader has finished reading the assignment. The ReadingAssignments are collected into WeeklyAssignment arrays. I want to have the user be able to touch a label and have a checkmark appear and show the assignment as completed. I would like this touch to also update the .checked property to true so I can persist the data.
So, I am trying to have the gestureRecognizer call the labelTicked() method. This works and prints to the console. However, when I try to pass in the assignment parameter, it compiles, but crashes on the touch with an "unrecognized selector" error. I have read every topic i can find here, and haven't found the solution. They all say ":" signifies a Selector with parameters, but still no go.
Can you see what I am doing wrong?
func configureCheckmark(cell: UITableViewCell, withWeeklyAssignment assignment: WeeklyAssignment) {
let checkLabel = cell.viewWithTag(1002) as! UILabel
checkLabel.userInteractionEnabled = true
let gestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("labelTicked:assignment"))
checkLabel.addGestureRecognizer(gestureRecognizer)
}
#objc func labelTicked(assignment: WeeklyAssignment) {
assignment.toggleCheckmark()
if assignment.checked {
label.text = "✔︎"
} else {
label.text = ""
}
}
I would also love to pass in the UILabel checkLabel so I can update it in the labelTicked() method.
Thanks for your help.
There are two distinct problems here:
The syntax for the selector is wrong; the : doesn't mark the beginning of a parameters part, it merely marks that this function takes parameters at all. So the tap recognizer should be initialized as UITapGestureRecognizer(target: self, action: "labelTicked:"). Easy fix. That is the good news.
The bad news: even with perfect syntax it will not work the way you set it up here. Your tap recognizer cannot pass a WeeklyAssignment object as a parameter. In fact, it cannot pass any custom parameter at all. At least, not like that.
However, you can pass it in the sender (which is usually the view the gesture recognizer is attached to). You can grab it by changing your method to
func labelTicked(sender: AnyObject) {
(note that AnyObject may be declared as a more specific type if you know exactly what to expect.)
Going through the sender, you could now theoretically infer which label it is that has been tapped, which data entity that labels corresponds to, and which state the checked property of that entity is in. I think this would become very convoluted very quickly.
Seemingly straightforward things becoming convoluted is usually a good sign that we should take a step back and look for a better solution.
I'd suggest dropping the whole GestureRecognizer approach at this point, and instead exploit the fact that each cell in a table view already comes with its own "tap recongizing" functionality out of the box: the didSelectRowAtIndexPath: method of the table view's delegate. There, you can easily use the supplied NSIndexPath to retrieve the corresponding model entity from the data source to read and modify its parameters as you see fit. Via cellForRowAtIndexPath: you can then get a reference to the correct cell and change its contents accordingly.
Update for Swift 3:
As the Swift language evolves and using String-based selectors (e.g. "labelTicked:") is now flagged as deprecated, I think it's appropriate to provide a small update to the answer.
Using more modern syntax, you could declare your function like this:
#objc func labelTicked(withSender sender: AnyObject) {
and initialize your gesture recognizer like this, using #selector:
UITapGestureRecognizer(target: self, action: #selector(labelTicked(withSender:)))
The correct selector for that function is labelTicked:. Furthermore, you can use a string directly as a selector. Thus:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: "labelTicked:")
But you can't arrange to pass an arbitrary object along to the method when the recognizer fires. A better way to do this is to create a subclass of UITableViewCell. Let's call it AssignmentCell. Give the subclass an assignment property, and move the labelTicked: method to AssignmentCell.
If you've designed the cell in your storyboard, you can add a tap recognizer to the label right in the storyboard, and wire the recognizer to the cell's labelTicked: method in the storyboard.
In your table view data source's tableView(_:cellForRowAtIndexPath:), after you've dequeued the cell, set its assignment property to the assignment for that row.

NSNotification for UIAlertController [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Is there an option to observe and get the information about appearing and disappearing?
I want to grayscale my elements like apple ui-elements by appearing of UIAlertController!
Since now i found out that the "_UIBackdropViewComputeAndApplySettingsNotification" was called and contains userInfo about the appearing view.
You are going to make the UIAlertController's view appear, so how can you not know? You don't need to observe it; you're doing it (by calling presentViewController...).
That takes of what happens when the alert appears. What about when it disappears? Well, it disappears because the user tapped a button. You get to write the handler for every button in the alert. So again, you know when the alert is disappearing, because your handler is running.
The solution is, everything works automatically. You just have to implement..
override func tintColorDidChange() {
self.setNeedsDisplay()
}
..and of course working with the tintColor
Thanks matt for quick answer!
To expand on the other answers: each of your UIView subclasses should implement tintColorDidChange to be notified of the change.
Here's a sample implementation:
class someLabel : UILabel {
override func tintColorDidChange() {
let isInactive = self.tintAdjustmentMode == UIViewTintAdjustmentMode.Dimmed
if (isInactive) {
// modify subviews to look disabled
self.textColor = UIColor.grayColor()
} else {
// modify subviews to look enabled
self.textColor = self.tintColor
}
}
}
A few other good code samples (albeit in Objective-C) can be found in this SO question.

Swift: IBAction to put image in UIImageView after a button is clicked

I'm working in Swift and I'm trying to create a simple IBAction that puts an image (that I've already loaded in my assets) into a UIImageView once a button is clicked.
I've control-dragged and hooked everything up and yet I'm getting this error:
"cannot convert expressions type '()' to type 'UIImage!'"
I'm a beginner so please explain all answers thoroughly.
My code:
#IBAction func colorBtnClicked(sender: UIButton) {
colorsPanel.image = "Red_colors_panel"
}
First of all you need to pass an UIImage to the .image property but there is a String object and this cause the error.
To read image from your project bundle you need to do it the the following way:
colorsPanel.image = UIImage(named: "Red_colors_panel.png") // and do not forget the extension

Resources