i'm new the forum and also new to the swift language. I've been playing around with xcode and wanted to create an app that uses a fenceloop to display the factors of a number as a "solution." The app currently uses a label to display, a text for input, and a button to initiate. I have what i think to be functioning code but i can't see to get it to work because from what i understand, i have to convert the input that's a string into an int. If anyone has any ideas how to get this working; since i feel like i've done what i can.
The problem in particular i am getting is it is saying that "Cannot convert value of type 'UITextField!; to expected argument type 'Int'. What i intend to happen is that on the button click, it solves for the factors of whatever is in the text box and displays it as a string in the label. Any help is appreciated!
import UIKit
class ViewController: UIViewController {
#IBOutlet var input1 : UITextField!
#IBOutlet var label : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func printFactors(n: Int) {
var result: String = ""
for i in 1...n {
guard n % i == 0 else {continue}
result += i == 1 ? "1" : " and \(i)"
}
print(result)
let outputText = printFactors(n: input1)
label.text = outputText
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You have a lot of issues and confusion in your printFactors method. Lets split it up and setup things properly.
First, make a separate method to do the math:
func calculateFactors(n: Int) -> String {
var result: String = ""
for i in 1...n {
guard n % i == 0 else {continue}
result += i == 1 ? "1" : " and \(i)"
}
print(result)
return result
}
Now lets setup the button action:
#IBAction func factorAction(sender: UIButton) {
if let text = input1.text {
if let num = Int(text) {
let factor = calculateFactors(n: num)
label.text = factor
} else {
// Show the user that the entered text isn't a number
}
} else {
// There's no text
}
}
Setup your button to use the new factoryAction: method instead of the old printFactors: method.
Swift 3
Can reduce this code down to two lines with some functional magic.
func factors(of number: Int) -> [Int] {
return (1...number).filter { number % $0 == 0 }
}
print(factors(of: 24))
Related
In ViewController - I have two text fields, like text field for text wihch user wants to reverse and text field for exclusions, and result-UILabel which shows the result.
In first text field user typing some text for reverse and result-UILabel shows the result of reversed text.
In the second text field, I want to make an exception for letters which shouldn't be reversed in result-UILabel. They should be untouchable in the word of the reverse at the time of reversing the text from the first field and should remain in their places.
The model function is in another swift file in another class.
Model function:
import Foundation
class ReverseWords {
public func reverse(textField: String) -> String {
if textField.isEmpty {
return ""
}
return textField.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: " ")
.map { String ( $0.reversed() ) }
.joined(separator: " ")
}
}
Using model function for first text field in ViewController:
resultLabel.text = reverseWords.reverse(textField:
reverseTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines))
Example:
First text field (for reverse) print:
FogmEistEr
Second text field (for exclusions) letters which should be untouchable of reverse, print:
E
And result label shows:
rtsiEmgoEF
How can I implement this?
How can I call exceptionTextField in model to check his characters inside?
Actually, I don't want to do this between classes, but I would like to look at the solution.
I think it would be better to do it in ViewController, but I got confused…
Have you any ideas, how to implement this?
I'd just make an extension on String:
extension String {
func reversed(omittingCharactersIn characterSet: CharacterSet) -> String {
var reversed = reversed()
.filter { String($0).rangeOfCharacter(from: characterSet) == nil }
let excluded = enumerated()
.filter { String($0.element).rangeOfCharacter(from: characterSet) != nil }
for (i, char) in excluded {
reversed.insert(char, at: reversed.index(reversed.startIndex, offsetBy: i))
}
return String(reversed)
}
}
All this is doing is reversing all of the characters right away, but removing any characters that should not be reversed. Then it finds and maintains the indices and characters should not move. Finally, it inserts the characters that should not be reversed back to their original position.
Usage:
let text = "FogmEistEr"
let omit = "E"
print(text.reversed(omittingCharactersIn: CharacterSet(charactersIn: omit)))
Prints:
rtsiEmgoEF
Here's how I'd plug it into a viewController assuming the reversal would happen either by a button push or by the text simply changing:
class ViewController: UIViewController {
#IBOutlet weak var originalTextField: UITextField!
#IBOutlet weak var exclusionTextField: UITextField!
#IBOutlet weak var reversedLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
originalTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
exclusionTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
}
#objc func textChanged(_ sender: UITextField) {
tryReverse()
}
#IBAction func didTapButton(_ sender: UIButton) {
tryReverse()
}
private func tryReverse() {
guard let originalText = originalTextField.trimmedTextNilIfEmpty,
let exclusionText = exclusionTextField.trimmedTextNilIfEmpty else {
reversedLabel.text = ""
return
}
reversedLabel.text = originalText.components(separatedBy: " ")
.map {
$0.reversed(omittingCharactersIn: CharacterSet(charactersIn: exclusionText))
}.joined(separator: " ")
}
}
extension UITextField {
var trimmedTextNilIfEmpty: String? {
if let trimmed = text?.trimmingCharacters(in: .whitespacesAndNewlines) {
return trimmed.isEmpty ? nil : trimmed
}
return nil
}
}
Here you can take reference for logic (It can be optimized). We can pass exclude reverse function. Rather than put this logic in the view controller I would suggest keeping the logic in ReverseWords class.
class ReverseWords {
public func reverse(textField: String, excludeWord: String) -> String {
if textField.isEmpty {
return ""
}
return textField.trimmingCharacters(in: .whitespacesAndNewlines)
.components(separatedBy: " ")
.map { $0 == excludeWord ? String($0) : reverseWordWithExclude(currentWord: String($0), excludeWord: excludeWord) }
.joined(separator: " ")
}
private func reverseWordWithExclude(currentWord: String, excludeWord: String) -> String {
// return direct reversed string if the exclude word not contain in string
if !currentWord.contains(excludeWord) {
return String(currentWord.reversed())
}
// Replace whole exception word with single space char which is never included in the current word.
// Easy to find the current index for a single space or for a char.
let replaceWord = currentWord.replacingOccurrences(of: excludeWord, with: " ")
var reverseString = ""
var exceptionIndexes: [Int] = []
// Find the index of exclude word and reverse string without include exclude word
replaceWord.enumerated().forEach { index, char in
if char == " " {
exceptionIndexes.append(index)
} else {
reverseString.insert((char), at: reverseString.startIndex)
}
}
// Now replace single space with actual exclude word at their position.
exceptionIndexes.forEach{ index in
reverseString.insert(contentsOf: excludeWord, at: reverseString.index(reverseString.startIndex, offsetBy: index))
}
return reverseString
}
}
My goal is to use a button (that contains multiple messages) to trigger a text (making a marker such as first click will be method 1, second click will be method 2) correspondingly added at the end of the my data (after joined(separator: "~")) so that it could help me to analyze which button was clicked when I look back at the data.
Currently, I have a struct that will output the data:
struct CaptureData {
var vertices: [SIMD3<Float>] //A vector of three scalar values. It will return a list of [SIMD3<Float>(x,y,z)]
var mode: Mode = .one
mutating func nextCase() { // the data method will be changed
mode = mode.next()
}
var verticesFormatted : String { //I formatted in such a way so that it can be read more clearly without SIMD3
let v = "<" + vertices.map{ "\($0.x):\($0.y):\($0.z)" }.joined(separator: "~") + "trial: \(mode.next().rawValue)"
return "\(v)"
}
}
Based on #Joshua suggestion
enum Mode: String, CaseIterable {
case one, two, three
}
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
var nextCase: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
#discardableResult
func next() -> Self {
return self.nextCase
}
}
And the button is alternating the messages after each click,
var x = 0
var instance = CaptureData(vertices: [SIMD3<Float>])
// Next button for changing methods
#IBAction func ChangingTapped(_ btn: UIButton) {
if(x==0){
Textfield.text = "changing to driving"
}
else if(x==1){
Textfield.text = "changing to walking"
instance.nextCase()
}
else{
Textfield.text = "changing to cycling"
instance.nextCase()
}
x += 1
}
Updates: I am able to print one of the methods , .two (method two), after separator: "~". However, at the moment I am still not be able to click button to switch the case in the data.
The main problem is the initialization of variables. I am not able to define var instance = CaptureData(vertices: [SIMD3<Float>]) because it comes with error: Cannot convert value of type '[SIMD3<Float>].Type' to expected argument type '[SIMD3<Float>]'
I am sorry if my explanation is a bit messy here. I am trying to describe the problem I have here. Let me know if there is anything missing! Thank you so much in advance.
Enums is a data type that is more like a constant but much more readable.
An example will be passing in a status to a function.
enum Status {
case success
case failure
}
func updateStatus(_ status: Status) {
statusProperty = status
}
// somewhere in your code
instance.updateStatus(.success)
versus using an Int as a value.
func updateStatus(_ status: Int) {
statusProperty = status
}
// somewhere in your code
instance.updateStatus(1) // eventually you'll forget what this and you'll declare more of a global variable acting as constant, which technically what enums are for.
Enums in swift are a bit different though, much more powerful. More info about enums here
Back to the topic.
enum Mode: String, CaseIterable {
case one, two, three
}
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
var nextCase: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
#discardableResult
func next() -> Self { // you don't need to update self here, remember self here is one of the items in the enum, i.e. one, so assigning one = two just doesn't work.
return self.nextCase
}
}
// The data struct
struct CaptureData {
var mode: Mode = .one
// we add a mutation function here so we can update the mode
mutating func nextCase() { // the data your concern about, that can actually mutate is the mode property inside CaptureData struct.
mode = mode.next()
}
}
So lets say somewhere in the app you can use it like this you initialised an instance of CaptureData:
var instance = CaptureData() // Don't forget it should be var and not let, as we are updating its property.
instance.nextCase() // get the next case, initially it was .one
print(instance.mode) // prints two
instance.nextCase() // from .two, changes to .three
print(instance.mode) // prints three
Hope this helps.
I am trying to set up questions with a text field for answers. Only after the exact answer has been entered can the next question be shown. I'm getting an error code with "if answerField == answers[currentQuestionIndex]" I believe I need to have allowances for what can be entered as answers. I'm stuck and could use some help in the right direction. thank you
#IBAction func answerField(sender: AnyObject) {
for index in 1...5 {
if answerField == answers[currentQuestionIndex] {
++self.currentQuestionIndex
if self.currentQuestionIndex == self.questions.count {
self.currentQuestionIndex = 0
}
}
}
}
let questions: [String] = ["From what is cognac made?", "What is 7+7?", "What is the capital of Vermont?"]
let answers: [String] = ["Grapes", "14", "Montpelier"]
override func viewDidLoad() {
super.viewDidLoad()
currentQuestion.text = questions[currentQuestionIndex]
}
answerField as you've shown it here is not a UITextField; it is a function. That is what the error is telling you: A function that takes AnyObject as a parameter and returns nothing ((AnyObject)->()) can't be compared to a String.
I think perhaps what you wanted to do was create an outlet (not an action) for your answer field:
#IBOutlet weak var answerField: UITextField! // Make sure you actually hook this up to your text field in the storyboard.
Then, listen for changes to the content of the text field:
override func viewDidLoad()
{
super.viewDidLoad()
answerField.addTarget(
self,
action: #selector(answerChanged(_:)),
forControlEvents: .EditingChanged)
currentQuestion.text = questions[currentQuestionIndex]
}
And then handle changes to your answer field text:
func answerChanged(sender: AnyObject)
{
if (answerField.text ?? "") == answers[currentQuestionIndex]
{
currentQuestionIndex = currentQuestionIndex + 1 < questions.count ? currentQuestionIndex + 1 : 0
currentQuestion.text = questions[currentQuestionIndex]
}
}
Or something along those lines.
If you answerField variable is UIText field then you need to use its text. The is an optional property so you also need to unwrap it
if (answerField.text ?? "") == answers[currentQuestionIndex]
From error code mentioned seems like you don't have variable answerField and you are trying to compare function itself to String, that doesn't make any sense
Im quite new to programming, so hopefully someone can explain this to me in plain english..
Im trying to build an app in Swift that tells you wether the number inputted is a prime number or not. If it isn't prime, it should also tell you the factors of the numbers, e.x. if the user inputs 6, it tells you that 6 isn't a prime number, and apart from being divisible by 0, 1 and itself, its also divisible by 2 and 3. The code written until now is as follows:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var outputMessage: UILabel!
#IBAction func checkButton(sender: AnyObject) {
var isPrime = true
var inputNumber = textField.text.toInt()
var multiples:Int
if (inputNumber != nil) {
if (inputNumber <= 0) {
outputMessage.text = "Neither 0 nor negative numbers are considered prime numbers!"
textField.resignFirstResponder()
} else {
if (inputNumber == 1) {
outputMessage.text = "1 isn't a prime number!"
textField.resignFirstResponder()
}
else {
for var i = 2; i < inputNumber; ++i {
if (inputNumber! % i == 0) {
// Number is not prime
isPrime = false
multiples = i
}
}
}
if (isPrime == true) {
outputMessage.text = "Yup, that's a prime number!"
textField.resignFirstResponder()
} else {
outputMessage.text = "That number isn't prime. Apart from 1, 0 and itself, the number is also divisible by \(multiples) "
textField.resignFirstResponder()
}
}
} else {
outputMessage.text = "Please enter a number!"
textField.resignFirstResponder()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Towards the end, where the output message says "That isn't a prime. Apart from 0, 1 and itself, the number is divisible by (multiples)"
The code crashed here - it says Variable 'multiples' used before being initialized.
Can anyone help?
Thanks a lot!!
Error messages in Swift are frequently misleading. The real issue is that multiples is not initialized when you declare it.
In general, in Swift, variables need to be initialized when they are declared. There are a couple of exceptions: 1) optionals don't need to be initialized as they are nil if they are not explicitly initialized, 2) variables declared in a class can be initialized in the initializer.
To fix the error, assign multiples an initial value:
var multiples:Int = 0
This will only show you 1 multiple of the number. If you want all of them, make multiples an array:
var multiples:[Int] = []
Then append the values to the array when you have a new multiple:
multiples.append(i)
This question already has answers here:
SourceKitService Terminated
(34 answers)
Closed 8 years ago.
I was testing swift language.
Suddenly xcode terminated without showing error.
But got the following message:
Source kit service terminated editor functionality temporarily limited
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.myfunction()
//ViewController.classFunc()
//myfunctionWithArg()
//myfunctionWithArg(name: "hashim")
//learnSwitch()
self.learnClosure()
/*
let anInstance = MyClass()
anInstance.aFunction()
let someVehicle = Vehicle()
println(someVehicle.description)
someVehicle.description = "test"
let aCycle = Cycle()
println(aCycle.description)
*/
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func learnClosure(){
let retValue = jediGreet("old friend")
println(retValue)
println(retValue.0)
println(retValue.1)
let train = jediTrainer("hashim")
println(train("new programming swift", 3))
println((jediTrainer("hashim"))("Obi Wan", 3))
var names = ["fashim","hashim","ashim","bashim","cashim","dashim"]
sort(names, { (s1:String,s2:String)-> Bool in
println("test arg1:\(s1), arg2:\(s2)")
return s1>s2 } )
sort(names, >)
println(sort(names, <))
/*
let myadd = { (sum:Int,number:Int)->Int in
return (sum + number)
}
*/
// let myadd = { ($0 + $1) }
// println("sum is \(myadd(3,4))")
let padawans = ["Knox", "Avitla", "Mennaus"]
println( padawans.map({
(padawan: String) -> String in
"\(padawan) has been trained!"
}))
var numbers = [10,1,20,123,50]
println("before \(numbers)")
mySort(numbers,{
(num1:Int,num2:Int) -> Bool in
return num1 > num2
})
println("after \(numbers)")
}
func mySort( numbers:Int[],compare:((Int,Int)->Bool))
{
//Write your login to sort numbers using comparator method
var tmp:Int
var n = numbers.count
for(var i=0;i<n;i++)
{
for(var j=0;j<n-i-1;j++)
{
if(numbers[j] > numbers[j+1])
{
tmp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=tmp;
}
}
}
}
func repeat (count:Int,task:()->()){
for i in 0..count{
task()
}
}
func jediGreet(String) -> (farewell: String, mayTheForceBeWithYou: String) {
return ( "name" , " May the (ability) be with you.")
}
func jediTrainer (caller:String) -> ((String, Int) -> String) {
func train(name: String, times: Int) -> (String) {
return "\(name) has been trained in the Force \(times) times calling \(caller)"
}
return train
}
}
This can happen due to several reason in xcode (it is just because swift is still in beta) . In your case just comment the line // println(train("new programming swift", 3)). If you want to get this functionality split that line of code into two