How to break up expression into distinct sub-expressions? - swift

I got this error in Swift
"The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions"
Here is the code that is throwing the error.
let obj = self.AddressList[indexPath.row] as! Address
// let a:String! = obj.street+" ,"+obj.city+" "+obj.country
// let b:String! = obj.country
StaticData.singleton.cardAddress = obj.street+" ,"+obj.city+" "+obj.country
StaticData.singleton.AddressID = obj.id
StaticData.singleton.cart_addresstotal = obj.total_amount
StaticData.singleton.cart_addressFee = obj.delivery_fee
DispatchQueue.main.async {
self.dismiss(animated:true, completion:nil)
}
in particular it is this portion of the code in which the error is pointing towards:
StaticData.singleton.cardAddress = obj.street+" ,"+obj.city+" "+obj.country

Just replace the + operator with String concatenation. In general, using String concatenation is the preferred approach over using the + operator.
StaticData.singleton.cardAddress = "\(obj.street) ,\(obj.city) \(obj.country)"

Related

Cannot convert value of type '[Message]' to expected argument type 'Message'

I'm following this tutorial and I'm getting the error that you can see in the title, here is my code:
func loadData()
{
let delegate = UIApplication.shared.delegate as? AppDelegate
if let context = delegate?.persistentContainer.viewContext
{
if let friends = fetchFriends()
{
messages = [Message]()
for friend in friends
{
print(friend.name) // This line btw for some reason is giving me: Expression implicitly coerced from 'String?' to Any
let fetchRequest:NSFetchRequest<Message> = Message.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
fetchRequest.predicate = NSPredicate(format: "friend.name = %#", friend.name!)
fetchRequest.fetchLimit = 1
do
{
let fetchedMessages = try(context.fetch(fetchRequest))
messages?.append(fetchedMessages)
// This above line is the line which is giving me this error:
//Cannot convert value of type '[Message]' to expected argument type 'Message'
}
catch let err
{
print(err)
}
}
}
}
}
As you can see from about 13min my code does not look exactly the same, since the video is a bit old and using an older version of swift.
I'm hoping someone can help me to solve the error since I do not know what to do, thank you in advance.
try below line
messages.append(contentsOf: fetchedMessages)
instead of: messages.append(fetchedMessages)
append is to append individual elements to an array. You can use += to concatenate two arrays.
messages! += fetchedMessages
If messages is of optional type, you can force unwrap it because you know you have already set it to an empty array, but frankly, I would no make messages optional - just initialise it to []

Cannot convert value of type 'NSRange'(aka'_NSRange') to expected argument type 'Range<Data.Index>' (aka 'Range<int>

there. I am a beginner in Swift and am trying to convert an older program to Swift3. I´ve managed to fix a bunch of errors, but I cannot get this function to work.
fileprivate func extractEntitlements(_ entitlementData: Data) -> NSDictionary? {
var originalEntitlementsData = entitlementData
let xmlStart = "<?xml".data(using: String.Encoding.ascii, allowLossyConversion: true)
let bytes = (originalEntitlementsData as NSData).bytes
for i in 0...(originalEntitlementsData.count - xmlStart!.count) {
if memcmp((xmlStart! as NSData).bytes, bytes + i, Int(xmlStart!.count)) == 0 {
let end = originalEntitlementsData.count - i
**originalEntitlementsData = originalEntitlementsData.subdata(in: NSMakeRange(i, end))**
break;
}
}
return NSString(data: originalEntitlementsData, encoding: String.Encoding.ascii.rawValue)?.propertyList() as? NSDictionary
}
Here is the error I get:
There are a bunch of questions regarding this error, but I am not being successful implementing a solution. Any tips on how I should proceed?
Thanks guys!
Ranges are more complicated and simpler at the same time in swift.
You want subdata(in: start..<end), which makes a Range<Int>, which is the type you need. However, in this case start and end refer to the beginning and end indexes of the range, not the location and length as you pass to NSMakeRange().
As #jrturton already said, subdata(in:) takes a Range<Int> argument,
so it should be
originalEntitlementsData = originalEntitlementsData.subdata(in: i..<i+end)
in your case. But note that all the conversions to NSData, taking
the .bytes, explicit loop and memcmp are not needed if you
take advantage of the existing range(of:) method of Data:
var originalEntitlementsData = entitlementData
let xmlStart = "<?xml".data(using: .utf8)!
if let range = originalEntitlementsData.range(of: xmlStart) {
originalEntitlementsData = originalEntitlementsData.subdata(in: range.lowerBound..<originalEntitlementsData.endIndex)
// Alternatively:
// originalEntitlementsData.removeSubrange(0..<range.lowerBound)
}

swift 3 loop error (taking variable and adding it by itself)

My code does not work right now. I am trying to take names and add it by itself in the loop but the complier is giving me a error message and the code is not being printed.
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
print((names[i]) + names[i])
}
Because Any doesn't have + operator.
This will give you the result you expected.
If you want to add 2 values and print the result, you need to cast Any to calculatable like Double
let names = [Double(2),3,8] as [Any]
let count = names.count
for i in 0..<count {
if let value = names[i] as? Double {
print(value + value)
}
}
The use of as [Any] makes no sense. You can't add two objects of type Any which is probably what your error is about.
Simply drop it and your code works.
let names = [Double(2),3,8]
let count = names.count
for i in 0..<count {
print(names[i] + names[i])
}
Output:
4.0
6.0
16.0
Better yet:
let names = [Double(2),3,8]
for num in names {
print(num + num)
}

Value of type 'String' has no member indices

I am trying to migrate my Swift 2.2 code to Swift 3(beta) and I am getting the following error in the below code after migrating to Swift 3.0 ,"Value of type 'String' has no member indices"
Would require help on the following were routePathComponent is a String.
After Migrating
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substring(with: routePathComponent.indices.suffix(from: routePathComponent.characters.index(routePathComponent.startIndex, offsetBy: 1)))
}
Before Migrating
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substringWithRange(routePathComponent.startIndex.advancedBy(1)..<routePathComponent.endIndex)
let variableValue = component.URLDecodedString()
if variableKey.characters.count > 0 && variableValue.characters.count > 0 {
variables[variableKey] = variableValue
}
}
If you want to omit the first character if it's a colon, that's the Swift 3 way
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substring(from: routePathComponent.index(after :routePathComponent.startIndex))
}
The equivalent of your other example in the comment is
if let endingQuoteRange = clazz.range(of:"\"") {
clazz.removeSubrange(endingQuoteRange.upperBound..<clazz.endIndex)
...
}
You can use dropFirst() if you want just drop first character from String.
if routePathComponent.hasPrefix(":") {
let variableKey = String(routePathComponent.characters.dropFirst())
}
indices is property of Collection types. String is not Collection since v.2.3.
Use .characters property, which returns Collection of characters of the String.
var routePathComponent = ":Hello playground"
if routePathComponent.hasPrefix(":") {
let variableKey = routePathComponent.substringFromIndex(routePathComponent.startIndex.advancedBy(1))
//print(variableKey)
}
This should do the trick

Substrings in Swift

I'm having a problem with understand how I can work with substrings in Swift. Basically, I'm getting a JSON value that has a string with the following format:
Something
I'm trying to get rid of the HTML anchor tag with Swift so I'm left with Something. My thought was to find the index of every < and > in the string so then I could just do a substringWithRange and advance up to the right index.
My problem is that I can't figure out how to find the index. I've read that Swift doesn't support the index (unless you extend it.)
I don't want to add CPU cycles unnecessarily. So my question is, how do I find the indexes in a way that is not inefficient? Or, is there a better way of filtering out the tags?
Edit: Converted Andrew's first code sample to a function:
func formatTwitterSource(rawStr: String) -> String {
let unParsedString = rawStr
var midParseString = ""
var parsedString = ""
if let firstEndIndex = find(unParsedString, ">") {
midParseString = unParsedString[Range<String.Index>(start: firstEndIndex.successor(), end: unParsedString.endIndex)]
if let secondStartIndex = find(midParseString, "<") {
parsedString = midParseString[Range<String.Index>(start: midParseString.startIndex, end: secondStartIndex)]
}
}
return parsedString
}
Nothing too complicated. It takes in a String that has the tags in it. Then it uses Andrew's magic to parse everything out. I renamed the variables and made them clearer so you can see which variable does what in the process. Then in the end, it returns the parsed string.
You could do something like this, but it isn't pretty really. Obviously you would want to factor this into a function and possibly allow for various start/end tokens.
let testText = "Something"
if let firstEndIndex = find(testText, ">") {
let testText2 = testText[Range<String.Index>(start: firstEndIndex.successor(), end: testText.endIndex)]
if let secondStartIndex = find(testText2, "<") {
let testText3 = testText2[Range<String.Index>(start: testText2.startIndex, end: secondStartIndex)]
}
}
Edit
Working on this a little further and came up with something a little more idiomatic?
let startSplits = split(testText, { $0 == "<" })
let strippedValues = map(startSplits) { (s) -> String? in
if let endIndex = find(s, ">") {
return s[Range<String.Index>(start: endIndex.successor(), end: s.endIndex)]
}
return nil
}
let strings = map(filter(strippedValues, { $0 != "" })) { $0! }
It uses a little more functional style there at the end. Not sure I much enjoy the Swift style of map/filter compared to Haskell. But anyhow, the one potentially dangerous part is that forced unwrapping in the final map. If you can live with a result of [String?] then it isn't necessary.
Even though this question has been already answered, I am adding solution based on regex.
let pattern = "<.*>(.*)<.*>"
let src = "Something"
var error: NSError? = nil
var regex = NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators, error: &error)
if let regex = regex {
var result = regex.stringByReplacingMatchesInString(src, options: nil, range: NSRange(location:0,
length:countElements(src)), withTemplate: "$1")
println(result)
}