Swift 3 pass button/gesture recognizer action to other function using selector - swift3

I am having a problem with Swift 3 action selectors - or, I can say, with gesture recognizers.
Suppose I am in a table view where I am having dynamic data through a table cell. I have one button or gesture recogniser in the table view and I want to send data from that button or gesture to a different function.

Please try the below function, Hope it will work for you!!
func whereYouWant(){
let button = UIButton()
button.accessibilityElements = [data1,data2]//Here you can pass any thing in this array.
button.addTarget(self, action: #selector(testFunction), for: .touchUpInside)
}
//Here you can call this function through selector....
func testFunction(myButton:UIButton){
let firstData = myButton.accessibilityElements?[0] as? //Here you can do type cast According to you
let secondData = myButton.accessibilityElements?[1] as? //Here you can do type Cast According to you.
}

Related

Changing the thumb image of the slider conditionally in SwiftUI

I've been looking ways to change my thumb image of the slider conditionally for every value change. Since I was not able to find ways to locate the thumb, I used customised slider, using this article. It works perfectly fine, however, I'm not sure how to change the thumb image conditionally.
Please help.
Pretty new to SwiftUI.
You can use slider method,
setThumbImage(image, for: .normal)
setThumbImage(image, for: . highlighted)
And as per your requirement if you want to change image on value change you need to add your code like (code is from your attached link sample),
#objc func valueChanged(_ sender: UISlider) {
self.value.wrappedValue = Double(sender.value)
let arra: [UIImage?] = [UIImage(systemName: "heart"), UIImage(systemName: "pencil"), UIImage(systemName: "trash")]
sender.setThumbImage(arra.randomElement() as? UIImage, for: .normal)
sender.setThumbImage(arra.randomElement() as? UIImage, for: .highlighted)
}

SwiftUI change output format of `Text` using as `.timer`

Is there a way to change the output format of a Text using init(_ date: Date, style: Text.DateStyle)?
Using a .timer, the output is like: 0:42, but I want something like 00:00:42.
Background
I want to create a widget (iOS 14) where a timer is running, and as I think it's not a good idea to trigger a widget update every second, and this may even also not work reliably, at least that's not how widget are indented to be used.
So I thought about using this predefined timer functionality of Text.
I'm quite new to SwiftUI and don't really know about all the capabilities yet. So maybe I could create a similar custom Text-View by myself? Any ideas on how to achieve this?
Or asked differently: Is there a way to create such self-updating components by oneself, that also work in an iOS 14 widget? (Seems like using Timer.publish to update the View does not work in an iOS 14 widget)
No solution => Workaround
As of today, there doesn't seem to be a proper solution for this. But as the interest in a "solution" or workaround for this seems to be there, I'll just post what I ended up with, for now.
Code
Basically I just manually update the Text once a second, and calculate the difference from the reference date to "now".
struct SomeView: View {
let referenceDate = Date() // <- Put your start date here
#State var duration: Int = 0
let timer = Timer.publish(every: 1, on: .current, in: .common).autoconnect()
var body: some View {
Text(self.duration.formatted(allowedUnits: [.hour, .minute, .second]) ?? "")
.onReceive(self.timer) { _ in
self.duration = referenceDate.durationToNow ?? 0
}
}
}
extension Date {
var durationToNow: Int? {
return Calendar.current
.dateComponents([.second], from: self, to: Date())
.second
}
}
extension Int {
func formatted(allowedUnits: NSCalendar.Unit = [.hour, .minute]) -> String? {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = allowedUnits
formatter.zeroFormattingBehavior = .pad
return formatter.string(from: DateComponents(second: self))
}
}
WidgetKit limitations
This unfortunately does not work for WidgetKit, as the timer does not run or at least the UI does not refresh. So I ended up, only displaying minutes in the widget (which is kinda ok for my purpose) and just set an update in the "timeline" for each minute.

Creating Hashtags in swift

I am new to swift. I am trying to create a view where you can create hashtags. There is a UITextfield in which you type the word to be converted. On press of 'enter' or '#', it should automatically convert to hashtags and display in labels which are further stored in an array format.
I tried many tutorials but none of them seem to work.
UITextField's have a delegate that is pretty handy.
A really simple implementation would be to use the textFieldShouldReturn delegate method, you can use this to detect when the return button is pressed.
Tell your view controller that it is going to adopt the protocol like this:
class ViewController:UIViewController, UITextFieldDelegate {
...
Then tell your textfield where to delegate it's events, if you are making the textfield inside the view controller then use self to reference the view controller like this:
let textField = UITextField()
textField.delegate = self // IMPORTANT
self.view.addSubView(textField)
Then inside your view controller implement the textFieldShouldReturn method like so:
class ViewController:UIViewController, UITextFieldDelegate {
...
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let text = textField.text {
let hashtag = "#\(text)"
print("New hashtag is \(hashtag)")
}
return true // allows the default behaviour of return button, you can return false if you want the keyboard to remain on screen.
}
}
This solution does not account for the user entering more than one hashtag, nor does it remove white space etc.. you may need to think about formatting/validating this string before it is useable.
You may also want to consider looking at other existing questions that cover things like splitting strings and creating arrays.

passing instance of different sub classes onto another ViewController in Swift 3

I am trying to pass the instance of a created user onto to another view controller. The problem is the user that is passed over depends on type of user is selected. What I mean is I have created many sub-class of the main class User. So for example: Guest, VIP, Child etc and so when an instance is created on first page it is the sub class for that user that is created. I cannot get my head around how I pass the user to the second view controller without the second view controller user property being set to Type User. The problem is type User does not have all properties that sub classes have so in second page I am unable to access all properties that a sub class might have. This is example how I currently have it set:
First screen / view controller
var entrantData: People?
var entrantSelected: EntrantType = .none
#IBAction func generatePass(_ sender: UIButton) {
do{
switch entrantSelected {
case .freechildguest: entrantData = try Child(dateOfBirth: "\(dobTextField.text!)")
case .classicguest: entrantData = ClassicGuest()
case .maintenance: entrantData = try Maintenance(NameAddress(firstName: firstNameTextField.text, lastName: lastNameTextField.text, streetAddress: streetAddressTextField.text, city: cityTextField.text, state: stateTextField.text, zipCode: zipCodeTextField.text, entrantType: .maintenance))
default: break
}
} catch let error {
showAlert(title: "Error", message: "\(error)")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destViewController = segue.destination as? TicketViewController {
destViewController.dataFromForm = entrantData
}
}
Second screen / view controller
class TicketViewController: UIViewController {
var dataFromForm: People?
So in second View controller I now have the user data in dataFromForm but I want it to be in its sub class so I can get its properties that are only divided in its sub class. E.g. maintenance user has firstname property that child and classicGuest do not.
I suppose I could create all properties that sub class use in the User super class but I feel that defeats the point creating sub classes that have their own unique properties.
One way to solve this issue is to keep the property of type People on the TicketViewController and when trying to access a property that only a certain subclass has, try conditional down casting the People instance to the appropriate subclasses.
Here's a basic example of how you can achieve this:
if let vip = dataFromForm as? VIP {
//access VIP properties
} else if let guest = dataFromForm as? Guest {
//access guest properties
}
Another thing you can do is down cast to the protocol itself. This may make it easier in certain situations when there are multiple subclasses conforming to the same protocol.
if let entrant = entrantData as? Nameable {
fullNameLabel.text = entrant.fullName
}
So the above code would not be executed on child or classicGuest since they do not conform to the Nameable protocol.

iOS 5 Storyboard: NavigationViewController to TabbarController - Not working , Why?

I am using iOS5 with Storyboard and my scenes are like this :
NavigationCOntroller ->(Nav view 1) TableViewController -> TabBarController ->(Tab1)TableViewController
and similarly I more tabs under my TabBarController.
Now I go to Tab1 when user clicks on any row in my TableViewCOntroller and before PerformingSegue I want to send some data to my Tab1(TableViewController) like this
MyTableVController *tvc = segue.destinationViewController;
tvc.selectedObject = currentObject;
[UITabBarController setSelectedObject:]: unrecognized selector sent to instance 0x68c9450
Now why is it assuming that 'MyTableVController' is a UITabBarController and searching for setSelectedObject method ???
And how can I pass data to my TableViewCOntroller in this scenario ?
Thanks.
OK I have found solution to my problem , I did like this
UITabBarController *tabController = (UITabBarController *)segue.destinationViewController;
MyTableVController *tvc = (MyTableVController *)[viewControllers objectAtIndex:0];
And thats how you have your required viewcontroller and pass data to it.