Replaced String in Swift 2 - ios

So I'm trying to build my app for iOS 9 and am running into one problem. Before, I had a button that would take the string from a label and add it to a string that would take a person to lmgtfy and automatically search for the contents of the string, but now I'm running into an error with map(). Here is the code that worked in iOS 8:
#IBAction func googleButton() {
let replaced = String(map(originalString.generate()) { $0 == " " ? "+" : $0 })
if let url = NSURL(string: "http://google.com/?q=\(replaced)") {
UIApplication.sharedApplication().openURL(url)
}
print(replaced)
}
So now the error I'm getting says, "'map' is unavailable: call the 'map()' method on the sequence." Any ideas? Also, I'm not positive that link will work because it is supposed to be lmgtfy but I couldn't submit this question unless I changed the URL to google.

As of Swift 2, String no longer conforms to SequenceType, therefore you can't call generate on it. Instead you need to use the characters property to obtain a String.CharacterView, which does conform to SequenceType.
Also with Swift 2: map is a method in an extension of SequenceType. Therefore you call it like a method, instead of a free function:
let str = "ab cd ef gh"
let replaced = String(str.characters.map { $0 == " " ? "+" : $0 })
// "ab+cd+ef+gh"
You could also do:
let replaced = str.stringByReplacingOccurrencesOfString(" ", withString: "+")
// "ab+cd+ef+gh"

Related

Non-optional expression of type 'String' used in a check for optionals

I am getting this warning from Xcode Swift 5, here is my code I don't get what is wrong, I use this to remove any new line or tab at the end of my String (line)
My code:
let url: String = String(line.filter { !" \n\t\r".contains($0) })
UPDATE
I was doing it inside an if let and was using the type cast operator here is the solution and the rest of code and an example of the line value.
let line = " http://test.com/testing.php \n"
if let url: String = line.filter({!" \n\t\r".contains($0)}) as String?
{
//More action here
}
Thank you
to me this line looks good, but you may be missing the parentheses for the string filter method. Here's two ways I did it in playground. Let me know if this works for you, or how I can help further.
var line = "\t Hello, line removal \n \t Another new line \n"
let filteredClosure = line.filter { (char) -> Bool in
return !"\n\t\r".contains(char)
}
let filterShorthand = line.filter({!"\n\t\r".contains($0)})
With the line you provided, I would expect white-space to be removed too. If that's what you're looking for, add a space inside the filter string: " \n\t\r"

warning: 'characters' is deprecated: Please use String or Substring directly

characters - an instance property of String, is deprecated from with Xcode 9.1
It was very useful to get a substring from String by using the characters property but now it has been deprecated and Xcode suggests to use substring. I've tried to check around SO questions and apple developer tutorials/guidelines for the same. But could not see any solution/alternate as suggested.
Here is warning message:
'characters' is deprecated: Please use String or Substring
I've so many string operations are performed/handled using property characters.
Anyone have any idea/info about this update?
Swift 4 introduced changes on string API.
You can just use !stringValue.isEmpty instead of stringValue.characters.count > 0
for more information you get the sample from here
for e.g
let edit = "Summary"
edit.count // 7
Swift 4 vs Swift 3 examples:
let myString = "test"
for char in myString.characters {print(char) } // Swift 3
for char in myString { print(char) } // Swift 4
let length = myString.characters.count // Swift 3
let length = myString.count // Swift 4
One of the most common cases for manipulating strings is with JSON responses. In this example I created an extension in my watch app to drop the last (n) characters of a Bitcoin JSON object.
Swift 3:
func dropLast(_ n: Int = 0) -> String {
return String(characters.dropLast(n))
Xcode 9.1 Error Message:
'characters' is deprecated: Please use String or Substring directly
Xcode is telling us to use the string variable or method directly.
Swift 4:
func dropLast(_ n: Int = 0) -> String {
return String(dropLast(n))
}
Complete Extension:
extension String {
func dropLast(_ n: Int = 0) -> String {
return String(dropLast(n))
}
var dropLast: String {
return dropLast()
}
}
Call:
print("rate:\(response.USDRate)")
let literalMarketPrice = response.USDRate.dropLast(2)
print("literal market price: \(literalMarketPrice)")
Console:
//rate:7,101.0888 //JSON float
//literal market price: 7,101.08 // JSON string literal
Additional Examples:
print("Spell has \(invisibleSpellName.count) characters.")
return String(dropLast(n))
return String(removeLast(n))
Documentation:
You'll often be using common methods such as dropLast() or removeLast() or count so here is the explicit Apple documentation for each method.
droplast()
removelast()
counting characters
Use this characters because String stopped being a collection in Swift 2.0. However this is still valid code in Swift 4 but is no longer necessary now that String is a Collection again.
For example a Swift 4 String now has a direct count property that gives the character count:
// Swift 4
let spString = "Stack"
spString.count // 5
Examples for String and SubString.
String
Swift 4 String now directly get Element that gives the first character of String: (string.characters.first)
let spString = "Stack"
let firstElement = spString.first //S
SubString
Using SubString get first character.
let spstring = "Welcome"
let indexStartOfText = spstring.index(spstring.startIndex, offsetBy: 1)
let sub = spstring.substring(to: indexStartOfText)
print(sub) //W
That warning is just a top of the iceberg, there were a loot of string changes, strings are again a collection of characters, but we got soemthing new and cool, subStrings :)
This is a great read about this:
https://useyourloaf.com/blog/updating-strings-for-swift-4/
Just remove characters
For example:
stringValue.characters.count
to
stringValue.count
You can also use this code for dictionary grouping without using { $0.characters.first! }.
let cities = ["Shanghai": 24_256_800, "Karachi": 23_500_000, "Beijing": 21_516_000, "Seoul": 9_995_000]
let groupedCities = Dictionary(grouping: cities.keys) { $0.first! }
print(groupedCities)
func validatePhoneNumber(number:String) -> Bool{
if number.count < 10. //deprecated ->(number.characters.count)
{
return false;
}else{
return true;
}
}
You use directly .count and characters is deprecated.

Finding new line character in a String in "Swift 3"

In my app I am receiving some incoming data from a web service. In that data some wrong values can also be received like new line characters. I want to find in response string that if it contains a new line character or not.
Before Swift 3 I was able to do it like this
string.rangeOfString("\n")) == nil)
But in Swift 3 this methods is no longer available. However substring method is available which does with the help of Range.
I want to detect if my string contains "\n" how this would be accomplished using this method in Swift 3.
Short answer for Swift 5+
You can use
string.contains { $0.isNewline }
or KeyPath based syntax
string.contains(where: \.isNewline)
to detect if string contains any newline character.
Long answer
Swift 5 introduced couple of new properties on Character. Those simplify such tests and are more robust then simple check for \n.
Now you can use
myCharacter.isNewline
For complete list check Inspecting a Character section in Character docs
Example:
Character("\n").isNewline // true
Character("\r").isNewline // true
Character("a").isNewline // false
If you just want to know if it is there and don't care where it is, string.contains("\n") will return true if it is there and false if not.
You can also use
yourString.rangeOfCharacter(from: CharacterSet.newlines) != nil
which is more elegant as it's not using harcoded newline character string
Swift 3
string.range(of: "\n")
To check:
if string.range(of: "\n") == nil{
}
Or if you simply want to check the string contains \n or not, Then,
if !str.characters.contains("\n") {
}
.characters.contains() should do the trick:
let s1 = "Hi I'm a string\n with a new line"
s1.characters.contains("\n") // => true
let s2 = "I'm not"
s2.characters.contains("\n") // => false
let string:String = "This is a string"
if string.range(of: "\n") == nil {
print ("contains nil")
}
else {
print("contains new line")
}
perferctly working in swift 3.

urlNode.objectForKeyedSubscript("href") as? String - Swift 2.3 / Swift 3 error

My code crawls up an HTML page, searches for tags, reads a table on the website and populates a tableView. This worked like a charm in Swift 2.2 but since I've updated Cocoapods, I'm having this error that is refusing to go.
Here is my function:
if let secondColumn = rowElement.childAtIndex(1) as? HTMLElement {
title = secondColumn.textContent
.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
.stringByReplacingOccurrencesOfString("\n", withString: "")
if let urlNode = secondColumn.firstNodeMatchingSelector("a") {
if let urlString = urlNode.objectForKeyedSubscript("href") as? String {
url = NSURL(string: urlString)
if url == nil {
url = NSURL.init(string: "www.mywebsitelink.com")
}
}
}
}
The error is in: urlNode.objectForKeyedSubscript("href") as? String
Error:
Downcast from 'String?' to 'String' only unwraps optionals; did you
mean to use '!'?
This worked fine before and I haven't changed any code at all in this file.
Dependencies:
Alamofire
HTMLReader
Steps taken so far:
Updated code to Swift 2.3 and Swift 3 - doesn't work.
Cleaned code, deleted derived data, etc. - doesn't work.
Tried to flip versions of the dependencies to older versions - doesn't work.
Tried to change optional values i.e. added / removed '!' or '?', tried to change the function by removing 'if let' and just declaring it.
Images of Changes:
Error: conditional binding must have optional type, not string.
Error: unavailable for scripting
Please help.
Resolved it using this syntax:
if let urlString = urlNode["href"] {
}
Not sure if it is correct but getting rid of the text after the '.' seems to be working so far.
It looks to me like your original construct,
urlNode.objectForKeyedSubscript("href")
is of type String? (optional string) not some other type. Thus the as? cast is wrong. You should just use
if let urlString = urlNode.objectForKeyedSubscript("href")? {}

Binary operator '+' cannot be applied to two String operands

Hi i have a question about some code.
Okay, the problem is that i have some code that works in one function, but gives me an error in another function. The first code block is the function that it works in.
BTW, it is only one line:
#IBAction func searchPhotosByPhraseButtonTouchUp(sender: UIButton) {
if (!searchText.text.isEmpty) {
// 2: Replace spaces with +
var escapedSearchText:String = searchText.text.stringByReplacingOccurrencesOfString(" ", withString: "+")
// 3: API Method arguments
let methodArguments = [
"method": METHOD_NAME,
"api_key": API_KEY,
"text": escapedSearchText,
"format": FORMAT,
"nojsoncallback": NO_JSON_CALLBACK,
"extras": EXTRAS,
"safe_search": SAFE_SEARCH
]
// This line is the problem, if i make it in this function there is no problems
let urlString = BASE_URL + encodeParameters(params: methodArguments)
// 4: Call the Flickr API with these arguments
getImageFromFlickrBySearch(methodArguments)
}
else {
self.imageInfoLbl.text = "You did not write anything in the textfield"
}
}
So as you can see, in the code block above all is fine, but if i do it like this:
func getImageFromFlickrBySearch(methodArguments: [String: AnyObject]) {
// 5: Initialize session and url
...
// Here it gives me the error:
// Binary operator '+' cannot be applied to two String operands
let urlString = self.BASE_URL + encodeParameters(params: methodArguments)
...
}
I get a error.
I have removed the rest of the code from the second code block function for clarity.
I should probably say that BASE_URL is a constant.
The only difference of the functions, is that one is a #IBAction??
I'm not all too familiar with Swift but what could be causing your error is the methodArguments: [String: AnyObject]. In the function that works, Swift knows that all objects in the dictionary are String objects, but in the second function, their types are AnyObject.
If all of the key/value pairs are actually strings, change your parameter to methodArguments: [String: String] and see if that works.

Resources