id Identifier swift - ios

I have these lines of code in which if I stop on the X to delete an image I delete it. The problem is that if I have one or more of the same type of image, removing one of them, it also erases all the other identical ones. I think my problem is in calling the "forEach". What should I use?
While if the images are different, I delete correctly the single "sticker".
guard let id = gestureRecognizer.stringIdentifier else {return}
stickerArray.forEach { (sticker) in
if id == sticker.stickerIdentifier {
STKProbes.deleteSticker.send(from: nil, info: sticker.stickerIdentifier)
sticker.removeFromSuperview()
sticker.image = nil
if let index = stickerArray.index(of: sticker) {
stickerArray.remove(at: index)
}
}
}
func appendSticker(model: CoreSceneViewModel.AddSticker.ViewModel) {
let sticker = StickerView(frame: PlacementManager.categoryPlacement(forCategory: model.category, over: self.managedView.workbenchView), name: model.name)
self.managedView.controlsView.alpha = 0
self.managedView.closeButton.alpha = 0
self.stickerArray.append(sticker)
STKProbes.tapSticker.send(from: nil, info: sticker.stickerIdentifier)
sticker.image = model.sticker
sticker.contentMode = .scaleAspectFit
if kFreezeOldStickers {
for view in self.managedView.workbenchView.subviews {
if let grs = view.gestureRecognizers {
for gr in grs {
view.removeGestureRecognizer(gr)
}
}
}
}
draggingGesture = UIPanGestureRecognizer(target: self, action: #selector(dragging(gestureRecognizer:)))
sticker.addGestureRecognizer(draggingGesture)
pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinched(gestureRecognizer:)))
sticker.addGestureRecognizer(pinchGesture)
rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotated(gestureRecognizer:)))
sticker.addGestureRecognizer(rotationGesture)
tapGestureAlpha = UITapGestureRecognizer(target: self, action: #selector(setAlpha0(gestureRecognizer:)))
self.managedView.workbenchView.addGestureRecognizer(tapGestureAlpha)
tapGesture = TapGesture(target: self, action: #selector(tapped(gestureRecognizer:)))
tapGesture.idIdentifier = sticker.stickerIdentifier
sticker.addGestureRecognizer(tapGesture)
dTapGesture = DeleteTapGesture(target: self, action: #selector(cancelTapped(gestureRecognizer:)))
dTapGesture.stringIdentifier = sticker.stickerIdentifier
sticker.xButton.addGestureRecognizer(dTapGesture)
sticker.xButton.isUserInteractionEnabled = true
sticker.isUserInteractionEnabled = true
sticker.layer.zPosition = 0
draggingGesture.delegate = self
self.managedView.workbenchView.addSubview(sticker)

You can try
stickerArray.forEach {
if $0.xButton == gestureRecognizer.view {
$0.removeFromSuperview()
}
}
you may have similar stringIdentifier for items

Related

How to detect if UI Label was tapped?

I'm trying to make a choose-your-own adventure game that changes the text of two labels (the user choices) depending on which label the user taps. I figured I would just do a very nested if-else statement rather than bother with trying to implement a binary tree. I know how to attach the gesture recognizer to a label (I think):
let tapped1 = UITapGestureRecognizer(target: self, action: #selector(VCGame.usrChose1))
choice1.isUserInteractionEnabled = true
choice1.addGestureRecognizer(tapped1)
let tapped2 = UITapGestureRecognizer(target: self, action: #selector(VCGame.usrChose2))
choice2.isUserInteractionEnabled = true
choice2.addGestureRecognizer(tapped2)
and I can define what to do when the label is touched in the usrChose1 and usrChose2 functions, however, those functions only work once: the first time the function is chosen and my game has more than just one choice. From there, the labels will just do the same thing if the user touches them.
How would I go about having a condition inside the if-else statement that evaluates to true or false if label1 or label2 is tapped?
Here's the code for usrChoice1 and usrChoice2, for clarification
func usrChose1(sender : UITapGestureRecognizer) {
print("tap 1 working")
choice1.text = "choice1.1"
choice2.text = "choice1.2"
}
func usrChose2(sender : UITapGestureRecognizer) {
print("tap2 working")
choice1.text = "update2.1";
choice2.text = "update2.2"
}
Below image shows my requirement :
According to your requirement, I have tried the following:
I have made a dummy project with two labels inside a view controller
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var choice1Label: UILabel!
#IBOutlet weak var choiceLabel2: UILabel!
var tapStart: Bool = false
var levelType1: Level?
var levelType2: Level?
override func viewDidLoad() {
super.viewDidLoad()
let tapped1 = UITapGestureRecognizer(target: self, action: #selector(usrChose1))
choice1Label.isUserInteractionEnabled = true
choice1Label.addGestureRecognizer(tapped1)
let tapped2 = UITapGestureRecognizer(target: self, action: #selector(usrChose2))
choiceLabel2.isUserInteractionEnabled = true
choiceLabel2.addGestureRecognizer(tapped2)
setup()
}
var currentLevel1: Level?
var currentLevel2: Level?
func setup() {
let lb2Child1Child1 = Level(text: "2.1.1", subLevels: nil)
let lb2Child1Child2 = Level(text: "2.1.2", subLevels: nil)
let lb1Child1Child1 = Level(text: "1.1.1", subLevels: nil)
let lb1Child1Child2 = Level(text: "1.1.2", subLevels: nil)
let lb1Child2Child1 = Level(text: "1.2.1", subLevels: nil)
let lb1Child2Child2 = Level(text: "1.2.2", subLevels: nil)
let lb1Child1 = Level(text: "1.1", subLevels: [lb1Child1Child1, lb1Child1Child2])
let lb1Child2 = Level(text: "1.2", subLevels: [lb1Child2Child1, lb1Child2Child2])
let lb2Child1 = Level(text: "2.1", subLevels: [lb2Child1Child1, lb2Child1Child2])
let lb2Child2 = Level(text: "2.2", subLevels: nil)
levelType1 = Level(text: "1", subLevels: [lb1Child1, lb1Child2])
levelType2 = Level(text: "2", subLevels: [lb2Child1, lb2Child2])
choice1Label.text = levelType1!.text ?? ""
choiceLabel2.text = levelType2!.text ?? ""
}
func usrChose1(sender : UITapGestureRecognizer) {
if !tapStart {
currentLevel1 = levelType1
tapStart = true
}
if let subLevelsArray = currentLevel1?.subLevels {
print(subLevelsArray[0].text ?? "")
print(subLevelsArray[1].text ?? "")
choice1Label.text = subLevelsArray[0].text ?? ""
choiceLabel2.text = subLevelsArray[1].text ?? ""
currentLevel1 = subLevelsArray[0]
currentLevel2 = subLevelsArray[1]
}
}
func usrChose2(sender : UITapGestureRecognizer) {
//print("tap2 working")
// choice1Label.text = "update2.1";
//choiceLabel2.text = "update2.2"
if !tapStart {
currentLevel2 = levelType2
tapStart = true
}
if let subLevelsArray = currentLevel2?.subLevels {
print(subLevelsArray[0].text ?? "")
print(subLevelsArray[1].text ?? "")
choice1Label.text = subLevelsArray[0].text ?? ""
choiceLabel2.text = subLevelsArray[1].text ?? ""
currentLevel1 = subLevelsArray[0]
currentLevel2 = subLevelsArray[1]
}
}
}
I have made a class named Level to represent a single level and each level contains sublevels
Level.swift
import UIKit
class Level {
var text: String?
var subLevels: [Level]?
init(text: String, subLevels: [Level]?) {
self.text = text
self.subLevels = subLevels ?? nil
}
}
You have to add UITapGestureRecognizer in UILabel or UIView whatever is container.
Add 2 different Int variables in each functions usrChose1 and usrChose2 respectively, which will be work as a counter.
var i = 0
var j = 0
func usrChose1(_ recognizer: UITapGestureRecognizer) {
i++
print("Total clicked label 1 :::",i)
}
func usrChose2(_ recognizer: UITapGestureRecognizer) {
j++
print("Total clicked label 2 :::",j)
}

Material TextField previous next button

I am trying to get the previous/next arrow button on top of the keyboard when ever a textField is selected.
I have tried the following
textField0.tag = 0 // textField0 : TextField
textField0.addPreviousNextRightOnKeyboardWithTarget(self, rightButtonTitle: "Submit", previousAction: #selector(previousTextField(sender:)), nextAction: #selector(nextTextField(sender:)), rightButtonAction: #selector(saveNewPlan), titleText: nil)
textField1.tag = 1
textField1.addPreviousNextRightOnKeyboardWithTarget(self, rightButtonTitle: "Submit", previousAction: #selector(previousTextField(sender:)), nextAction: #selector(nextTextField(sender:)), rightButtonAction: #selector(saveNewPlan), titleText: nil)
The previous/next action selector defined as such.
func previousTextField(sender: AnyObject){
// I actually get the sender as IQBarButtonItem (subclass of UIBarButtonItem) instead of UITextField here
if let previousField = textField.superview?.viewWithTag(textField.tag - 1) as? UITextField {
_ = previousField.becomeFirstResponder()
}
}
func nextTextField(sender: AnyObject){
if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
_ = nextField.becomeFirstResponder()
}
}
It's throwing this error whenever I click on the button.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[IQKeyboardManagerSwift.IQBarButtonItem superview]: unrecognized selector sent to instance 0x7fc3775658e0'
Here's what the method do.
public func addPreviousNextRightOnKeyboardWithTarget( _ target : AnyObject?, rightButtonTitle : String, previousAction : Selector, nextAction : Selector, rightButtonAction : Selector, titleText : String?) {
//If can't set InputAccessoryView. Then return
if self.responds(to: #selector(setter: UITextField.inputAccessoryView)) {
// Creating a toolBar for phoneNumber keyboard
let toolbar = IQToolbar()
toolbar.doneTitle = rightButtonTitle
var items : [UIBarButtonItem] = []
let prev : IQBarButtonItem
let next : IQBarButtonItem
// Get the top level "bundle" which may actually be the framework
var bundle = Bundle(for: IQKeyboardManager.self)
if let resourcePath = bundle.path(forResource: "IQKeyboardManager", ofType: "bundle") {
if let resourcesBundle = Bundle(path: resourcePath) {
bundle = resourcesBundle
}
}
var imageLeftArrow : UIImage!
var imageRightArrow : UIImage!
if #available(iOS 10.0, *) {
imageLeftArrow = UIImage(named: "IQButtonBarArrowUp", in: bundle, compatibleWith: nil)
imageRightArrow = UIImage(named: "IQButtonBarArrowDown", in: bundle, compatibleWith: nil)
} else {
imageLeftArrow = UIImage(named: "IQButtonBarArrowLeft", in: bundle, compatibleWith: nil)
imageRightArrow = UIImage(named: "IQButtonBarArrowRight", in: bundle, compatibleWith: nil)
}
//Support for RTL languages like Arabic, Persia etc... (Bug ID: #448)
if #available(iOS 9.0, *) {
imageLeftArrow = imageLeftArrow?.imageFlippedForRightToLeftLayoutDirection()
imageRightArrow = imageRightArrow?.imageFlippedForRightToLeftLayoutDirection()
}
prev = IQBarButtonItem(image: imageLeftArrow, style: UIBarButtonItemStyle.plain, target: target, action: previousAction)
prev.accessibilityLabel = "Toolbar Previous Button"
next = IQBarButtonItem(image: imageRightArrow, style: UIBarButtonItemStyle.plain, target: target, action: nextAction)
next.accessibilityLabel = "Toolbar Next Button"
//Previous button
items.append(prev)
//Fixed space
let fixed = IQBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
if #available(iOS 10.0, *) {
fixed.width = 6
} else {
fixed.width = 20
}
items.append(fixed)
//Next button
items.append(next)
//Flexible space
items.append(UIView.flexibleBarButtonItem())
//Title button
let title = IQTitleBarButtonItem(title: shouldHidePlaceholderText == true ? nil : titleText)
items.append(title)
//Flexible space
items.append(UIView.flexibleBarButtonItem())
//Right button
let doneButton = IQBarButtonItem(title: rightButtonTitle, style: UIBarButtonItemStyle.done, target: target, action: rightButtonAction)
items.append(doneButton)
// Adding button to toolBar.
toolbar.items = items
toolbar.toolbarTitleInvocation = self.titleInvocation
// Setting toolbar to keyboard.
if let textField = self as? UITextField {
textField.inputAccessoryView = toolbar
switch textField.keyboardAppearance {
case UIKeyboardAppearance.dark:
toolbar.barStyle = UIBarStyle.black
default:
toolbar.barStyle = UIBarStyle.default
}
} else if let textView = self as? UITextView {
textView.inputAccessoryView = toolbar
switch textView.keyboardAppearance {
case UIKeyboardAppearance.dark:
toolbar.barStyle = UIBarStyle.black
default:
toolbar.barStyle = UIBarStyle.default
}
}
}
}

How to pass extra arguments in selector?

I have this piece of code
class func catchWeightList(catchWeightButton : UIButton, productCatchWeightList:NSArray){
let window = UIApplication.sharedApplication().keyWindow
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
let catchWeightVC = CatchWeight.init(nibName: "CatchWeight", bundle: nil,dataSource: productCatchWeightList, catchWeightButton: catchWeightButton)
if catchWeightVC.view.superview == nil {
let y = catchWeightButton.frame.origin.y+catchWeightButton.frame.height+64
catchWeightVC.view.frame = CGRectMake(catchWeightButton.frame.origin.x, y ,catchWeightButton.frame.width, 90)
window?.addSubview(catchWeightVC.view)
window?.addGestureRecognizer(tap)
}
else{
catchWeightVC.view.removeFromSuperview()
window?.removeGestureRecognizer(tap)
}
}
class func handleTap(sender: UITapGestureRecognizer? = nil) {
// catchWeightVC?.view.removeFromSuperview()
let window = UIApplication.sharedApplication().keyWindow
window?.removeGestureRecognizer(sender!)
}
How to pass catchWeightVC in handleTap?

Swift - Animate dynamically created UIImageView

Initially I had this code working when I was just animating the one UIImageView that I had. But then I changed it to animate several dynamically created UIImageViews, however since they are dynamically created inside a for loop, I'm finding it difficult to animate them as I did the initial one.
override func viewDidLoad() {
super.viewDidLoad()
var sprite: UIImage = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
for var i = 0; i < locations.count; i++ {
println(locations[i]["locationx"])
var locationx = locations[i]["locationx"] as String
var locationy = locations[i]["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite: UIImageView
mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
}
func flash() {
var mapSprite:UIImageView?
if mapSprite?.alpha == 1 {
mapSprite?.alpha = 0
} else {
mapSprite?.alpha = 1
}
}
This does not work as the mapSprite in the flash function is different to the one in the for loop. How can I refer to the one in the for loop and then animate it? Or would there be a better alternative to what I'm currently doing?
Many thanks!
EDIT
Using Xcode 6.2
You need to store the views into a property and then enumerate that property each time your timer event is fired
var sprites: [UIImageView]?
override func viewDidLoad() {
super.viewDidLoad()
var sprite = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
self.sprites = map(locations) {
var locationx = $0["locationx"] as String
var locationy = $0["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
return mapSprite
}
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
func flash() {
if let sprites = self.sprites {
for sprite in sprites {
sprite.alpha = sprite.alpha == 0 ? 1 : 0
}
}
}

How to release memory for UIImageView (Swift)

I got a problem with UIImage. I've manually added UIImageView objects to a scroll view. The problem is : when I have more than 50 images, memory will increase to around 200MB, and the app will be crash on iphone 4 or 4s. I want to release memory for images that is not in visible part when I receive Memory Warning to prevent crashing but I don't know how to release them with Swift. Help me please.
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadImage(index:Int){
if self.imgPaths.count == 0 {
println("Has not data")
actInd.stopAnimating()
return
}
var imgURL: NSURL = NSURL(string: self.imgPaths[index].stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()))!
let width:CGFloat = self.view.bounds.width
let height:CGFloat = self.view.bounds.height
var view:UIView = UIView(frame: CGRectMake(0, 0, width, height));
if let imgObj = self.dicData[index] {
}
else
{
println("imgURL \(imgURL)")
let request: NSURLRequest = NSURLRequest(URL: imgURL)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if error == nil {
let imgItem = UIImage(data: data)!
var te :Float = self.imgPaths.count > 0 ? Float(index + 1) / Float(self.imgPaths.count) : 1
self.progressView.setProgress(te, animated: true)
if let imgObj = self.dicData[index] {
if index < self.imgPaths.count - 1
{
var nextIndex:Int = index + 1
self.loadImage(nextIndex)
}
if(index == self.imgPaths.count - 1)
{
if self.currentImageIndex > 0
{
self.isAddedFirstImg = true
}
if !self.isAddedFirstImg
{
self.scrollViews[0].zoomScale = self.zoomScales[0]
self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
self.isAddedFirstImg = true
}
self.actInd.stopAnimating()
println("loaded image")
}
}
else
{
self.dicData[index] = UIImageView(image: imgItem)
self.dicData[index]?.frame = CGRect(origin: CGPointMake(0.0, 0.0), size:imgItem.size)
// 2
self.scrollViews[index].addSubview(self.dicData[index]!)
self.scrollViews[index].contentSize = imgItem.size
// 3
var doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "scrollViewDoubleTapped:")
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.numberOfTouchesRequired = 1
self.scrollViews[index].addGestureRecognizer(doubleTapRecognizer)
var singleTapRecognizer = UITapGestureRecognizer(target: self, action: "scrollViewSingleTapped:")
singleTapRecognizer.numberOfTapsRequired = 1
singleTapRecognizer.numberOfTouchesRequired = 1
self.scrollViews[index].addGestureRecognizer(singleTapRecognizer)
var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
self.scrollViews[index].addGestureRecognizer(swipeRight)
var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeLeft.direction = UISwipeGestureRecognizerDirection.Left
self.scrollViews[index].addGestureRecognizer(swipeLeft)
// 4
var scrollViewFrame = self.scrollViews[index].frame
var scaleWidth = scrollViewFrame.size.width / self.scrollViews[index].contentSize.width
var scaleHeight = scrollViewFrame.size.height / self.scrollViews[index].contentSize.height
var minScale = min(scaleWidth, scaleHeight)
self.zoomScales[index] = minScale
self.scrollViews[index].minimumZoomScale = minScale
// 5
self.scrollViews[index].maximumZoomScale = 1.0
self.scrollViews[index].delegate = self
// 6
self.centerScrollViewContents(index)
dispatch_async(dispatch_get_main_queue(), {
println("downloaded image index: \(index) CH.\(self.chapterID)")
if(index == 0)
{
self.scrollViews[0].zoomScale = self.zoomScales[0]
self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
self.actInd.stopAnimating()
}
if index < self.imgPaths.count - 1 && !self.stopDownload
{
var nextIndex:Int = index + 1
self.loadImage(nextIndex)
}
if(index == self.imgPaths.count - 1)
{
if self.currentImageIndex > 0
{
self.isAddedFirstImg = true
}
if !self.isAddedFirstImg
{
self.scrollViews[0].zoomScale = self.zoomScales[0]
self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
self.isAddedFirstImg = true
}
self.actInd.stopAnimating()
println("loaded image")
}
})
}
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
}
Swift uses ARC (Automatic Reference Counting) to manage memory. To free something from memory, you must remove all references to that object. ARC maintains a count of the number of places that hold a reference to the object, and when that count reaches 0, the memory is freed.
In your case, your imageViews are stored in self.dicData[index] and they are added as subviews of self.scrollViews[index]. You will need to remove the imageView from its superview and from self.dicData. Once you do that, the memory will be freed.
If you have the index of the imageView you want to free:
self.dicData[index]?.removeFromSuperview()
self.dicData[index] = nil
in swift there is really good tool called "lazy"
you might wanted to study about lazy var its very handy when it comes down to the images and tableview (for your instance collectionview)
you will see a huge difference when its used from custom cell.
create a imageview e.g. lazy var imageViewer:UIImageView
my app was at about 150mb 200mb memory now its at 40~60mb try it!

Resources