Xcode 8.1 swift 3 take forever to compile this code - xcode

I have this class in a project which previously use swift 2.3. When i migrated the project to swift 3, xcode took forever to compile and i saw it stuck at this class. I can not build the whole project because of this class. Is there a way to modify this class so the project can be built, it took Xcode forever to compile this piece of code. If i removed several properties from MyClass, Xcode will quickly compile again. Anyone has any idea on how to solve this problem?
import Foundation
class MyClass: NSObject {
var id: String = ""
var uid: String = ""
var uname: String = ""
var fname: String = ""
var txt: String = ""
var hay: Float = 0
var flag = false
var long: Double = 0
var lat: Double = 0
var altitude: Double = 0
var course: Double = 0
var speed: Double = 0
var lname: String = ""
var city: String = ""
var country: String = ""
var sublocal: String = ""
var subarea: String = ""
var thumb: String = ""
var trash = false
var date: Double = 0
var updated: Double = 0
var furl: String = ""
func toAnyObject() -> Any {
return [
"id": id,
"uid": uid,
"uname": uname,
"fname": fname,
"txt": txt,
"hay": hay,
"flag": flag,
"long": long,
"lat": lat,
"altitude": altitude,
"course": course,
"speed": speed,
"lname": lname,
"city": city,
"country": country,
"sublocal": sublocal,
"trash": trash,
"subarea": subarea,
"thumb": thumb,
"date": date,
"updated": updated,
"furl": furl
]
}
}

Rewrite without the big dictionary literal. So:
func toAnyObject() -> Any {
var d = [String:Any]()
d["id"] = id
d["uid"] = uid
// ... and so on ...
return d
}

If you're not doing so already adding a -Xfrontend -debug-time-function-bodies compiler flag to your project will list the time required to compile each function. That can be a useful way to identify what exactly is slow in your build. (See http://irace.me/swift-profiling or https://thatthinginswift.com/debug-long-compile-times-swift/).
In your case the compiler is probably struggling to determine the type of your dictionary literal. Looking at each key and value and then trying to find the most appropriate common type for all of them. If you specified a type then I expect the compiler will only need to verify that your literal matches that type and compile much more quickly:
let result: [String: Any] = ["id": id, ...]
return result

Sometimes the compiler slows down when you do implicit typing. If you Explicitly add the type information then the compiler will not need to calculate it. I can see that the properties of your class mostly have type information but not all of them. In your toAnyObject method, it seems like you want your object represented as a dictionary, yet you are converting it to type Any.
You are making a dictionary literal and offering no type information. Explicitly casting with "as" can help a lot.
When you convert something to type Any, Objective-C interprets that as id. Normally a swift dictionary would be bridged to an NSDictionary for Objective-c, but you are forcing it to be of type Any. What reason would the compiler have to bridge this to an NSDictionary? It probably boxes it since it thinks it is a struct and objective-c can't use swift structs.
Try to not confuse the compiler.

Related

What should I put into FindAppointmentsAsync's &self parameter?

I'm new to rust and am trying to make use of the windows cargo. But I don't understand what I should set the &self parameter in the FindAppointmentsAsync function.
This is Cargo.toml:
[package]
name = "rust-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.windows]
version = "0.43.0"
features = [
"ApplicationModel",
"ApplicationModel_Appointments",
"Foundation_Collections",
]
This is main.rs:
use std::time::Duration;
use windows::{
core::*, ApplicationModel::Appointments::*, Foundation::{DateTime, TimeSpan},
};
fn main() -> Result<()> {
let rangestart = DateTime::default();
let rangelength = TimeSpan::from(Duration::new(60 * 60 * 24 * 30, 0));
println!("test");
unsafe {
let store = AppointmentStore();
let result = AppointmentStore::FindAppointmentsAsync(&store, rangestart, rangelength);
}
Ok(())
}
If let store = AppointmentStore::new(); the error is no function or associated item named 'new' found
If let store = AppointmentStore();, the error is expected 1 argument, found 0
If let store = AppointmentStore(""); the error is cannot initialize a tuple struct which contains private fields
You cannot create an AppointmentStore directly, as it has private fields and does not expose a constructor function.
Looking at the docs, there are two ways to get an AppointmentStore:
By calling clone on an existing one.
By calling RequestStoreAsync on an AppointmentManager or AppointmentManagerForUser.
AppointmentManager is a struct with no fields, so you can create one by simply doing:
let foo = AppointmentManager;
let bar = foo.RequestStoreAsync(/* insert params here */);
AppointmentManagerForUser also cannot be constructed directly, and is obtained by calling GetForUser on an AppointmentManager.

Protobuffer API for dynamic Enum Access

I want to know how to set an Enum value dynamically.
I have the following .proto file:
syntax = "proto3";
package garden;
option go_package = "proto/garden";
message Garden {
enum Flower {
Rose = 0;
Acacia = 1;
Firethorn = 2;
Nemophila = 3;
}
Flower flower = 1;
}
One way to set the enum is the following:
garden := pb.Garden{}
garden.Flower = pb.Garden_Rose
I want to generate my garden dynamically and only have the value "Rose". There is the value mapping but the following does not work:
garden := pb.Garden{}
garden.Flower = pb.Garden_Flower_value["Rose"] // gives error: cannot use garden.Garden_Flower_value[flower] (type int32) as type garden.Garden_Flower in assignment
garden.Flower = 0 // works somehow??
I assume that I can use the protoreflect package to set the value. Unfortunately, it is not clear to me yet how it works.
garden.Flower = protoreflect.EnumNumber(pb.Garden_Rose)
Furthermore, I want to set ".Flower" dynamically. I figured out how to set fields in a struct dynamically but lack the knowledge how to cast a protoreflect.Value to a reflect.Value type.
If someone wants to know how to do all of this dynamically. I finally figured it out:
func main() {
var garden = pb.Garden{}
var gardenProto = garden.ProtoReflect()
var fields = gardenProto.Descriptor().Fields()
var flower = fields.ByName(protoreflect.Name("flower"))
var rose = protoreflect.Name("Rose")
var enumValue = protoreflect.ValueOfEnum(protoreflect.EnumNumber(flower.Enum().Values().ByName(rose).Number()))
gardenProto.Set(flower, enumValue)
fmt.Print(garden.GetFlower())
}
When changing the string "Rose" to any of the other valid Flowers the enum is automatically updated. Furthermore, make sure that the field name is the one as specified in the .proto file. In this example it was flower.
Have you already tried this approach?
flower := "Rose"
garden := pb.Garden{}
garden.Flower = pb.Garden_Flower(pb.Garden_Flower_value[flower])
fmt.Println(garden.Flower.String()) // Rose

Swift 4: Strange Double and Float behaviour

Basically the problem is that in this example:
let d1 = NSNumber(value: 1.4);
let d2 = d1.doubleValue;
let f1 = NSNumber(value: Float(1.4));
let f2 = d1.floatValue;
d1 results 1.4
d2 results 1.3999999999999999
f1 results 1.4
f2 results 1.3999999999999998
Does anyone know why is that?
I'm trying to parse JSON file like:
{"name": "something", "version": 1.4}
with the following code:
let json = try (JSONSerialization.jsonObject(with: someData) as? [String: Any])!;
let version: Double = (json["version"] as! NSNumber).doubleValue;
OR
let version: Double = json["version"] as! Double;
OR
let version: Double = json["version"] as! Float;
And I just can't get 1.4...
Rounding the number is not a solution for me, because I want to write back this number to JSON file, that will be parsed by other programs/languages and needs to be exactly 1.4 in the file.
Any suggestions?
UPDATE: The problem is only with 1.1 and 1.4. There is no problem with 1.2, 1.3, 1.5
UPDATE 2: Serialization code:
let jsonDict: Dictionary<String,Any> = [
"name" : name,
"version" : version
];
let data = try? JSONSerialization.data(withJSONObject: jsonDict, options: []);
let jsonString = String(data:data, encoding:.utf8);
Ok, just to finalise the discussion.
At the end Decimal type did the trick. So I changed all variable references to Decimal and NOT NSDecimalNumber, because I got error that it doesn't comply with Codable and Decodable protocols. Maybe there is a workaround for this, but the easiest solution is just to stick with Decimal.
I would like to thanks to #JamesBucanek and #EricPostpischil for joining the discussion and help resolving this issue !!!
I had the same story.
I need to sent/receive float values using API endpoint. So I followed advice and changed Double to Decimal. It worked fine for encoding data, but not for decoding.
let value = "0.0006"
let decimal = Decimal(string: value)!
print(decimal) // 0.0006 OK
let jsonData = try JSONEncoder().encode(decimal)
print(String(data: jsonData, encoding: .utf8)!) // 0.0006 OK
let decocdedDecimal = try JSONDecoder().decode(Decimal.self, from: jsonData)
print(decocdedDecimal) // 0.0005999999999999998976 NOOOOOO!!!
However decode to Double works fine.
let decocdedDouble = try JSONDecoder().decode(Double.self, from: jsonData)
print(decocdedDouble) // 0.0006 OK
Also as was mentioned in answers above - Decimal should be inited with String to be encoded correctly
let decimal = Decimal(0.0006)
print(decimal) // 0.0005999999999999998976, it will be encoded same way
And ofcourse Double encoding not working as expected, otherwise we didn't have such issue.
// 0.00059999999999999995 for all cases ofcourse
print(String(data: try JSONEncoder().encode(0.0006), encoding: .utf8)!)
print(String(data: try JSONEncoder().encode(decocdedDouble), encoding: .utf8)!)
print(String(data: try JSONEncoder().encode(Double(value)!), encoding: .utf8)!)
So my dirty solution for now is to use wrapper for Double values. It will decode value as Double, but encode as Decimal(string:)
struct CodableDouble: Codable {
var value: Double
init(_ value: Double) {
self.value = value
}
init(from decoder: Decoder) throws {
value = try decoder.singleValueContainer().decode(Double.self)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let decimal = Decimal(string: "\(value)") ?? 0
try container.encode(decimal)
}
}
But I still don't understand what is the correct way to handle this issue. (except not using float values)

xcode: need to convert strings to double and back to string

this is my line of code.
budgetLabel.text = String((budgetLabel.text)!.toInt()! - (budgetItemTextBox.text)!.toInt()!)
the code works, but when I try to input a floating value into the textbox the program crashes. I am assuming the strings need to be converted to a float/double data type. I keep getting errors when i try to do that.
In Swift 2 there are new failable initializers that allow you to do this in more safe way, the Double("") returns an optional in cases like passing in "abc" string the failable initializer will return nil, so then you can use optional-binding to handle it like in the following way:
let s1 = "4.55"
let s2 = "3.15"
if let n1 = Double(s1), let n2 = Double(s2) {
let newString = String( n1 - n2)
print(newString)
}
else {
print("Some string is not a double value")
}
If you're using a version of Swift < 2, then old way was:
var n1 = ("9.99" as NSString).doubleValue // invalid returns 0, not an optional. (not recommended)
// invalid returns an optional value (recommended)
var pi = NSNumberFormatter().numberFromString("3.14")?.doubleValue
Fixed: Added Proper Handling for Optionals
let budgetLabel:UILabel = UILabel()
let budgetItemTextBox:UITextField = UITextField()
budgetLabel.text = ({
var value = ""
if let budgetString = budgetLabel.text, let budgetItemString = budgetItemTextBox.text
{
if let budgetValue = Float(budgetString), let budgetItemValue = Float(budgetItemString)
{
value = String(budgetValue - budgetItemValue)
}
}
return value
})()
You need to be using if let. In swift 2.0 it would look something like this:
if let
budgetString:String = budgetLabel.text,
budgetItemString:String = budgetItemTextBox.text,
budget:Double = Double(budgetString),
budgetItem:Double = Double(budgetItemString) {
budgetLabel.text = String(budget - budgetItem)
} else {
// If a number was not found, what should it do here?
}

Format Numbers in Textfields using Swift

I am trying to format a number from a UITextfield, as its being typed, to a decimal with commas.
I have done so with the following code:
#IBAction func editingDidBegin(sender : AnyObject)
{
costField.addTarget(self, action: Selector("textFieldDidChange:"), forControlEvents: UIControlEvents.EditingChanged)
}
func textFieldDidChange(theTextField:UITextField) -> Void
{
var textFieldText = theTextField.text.stringByReplacingOccurrencesOfString(",", withString: " ", options: NSStringCompareOptions.RegularExpressionSearch, range: Range(start: theTextField.text.startIndex, end: theTextField.text.endIndex))
var formatter:NSNumberFormatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
var formattedOutput = formatter.stringFromNumber(textFieldText.bridgeToObjectiveC().integerValue)
costField.text = formattedOutput
}
The problem with this, is after four digits are entered, everything after the comma is deleted. For example if I enter 4000 it formats to 4,000, then if I type another number like 8 it reformats to 48.
Is there another way I can format this, maybe through IB or how can I fix the code?
Replace the line with:
var textFieldText = theTextField.text.stringByReplacingOccurrencesOfString(",", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range: Range(start: theTextField.text.startIndex, end: theTextField.text.endIndex))
(I only removed the space between the double quotes).
Fact is, NSNumberFormatter doesn't like the added spaces in the string.
Works fine afterwards.
I know I am late to the party but this worked well for me.
var phoneNumber = " 1 (888) 555-5551 "
var strippedPhoneNumber = "".join(phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet))
It takes out the spaces and strips out the non decimal numeric characters.
The end result is "1888555551"
I've updated this answer to the newest version of swift. This borrows 90% from the two answers above however, also accounts for nil exception from the textfield when the textfield is cleared.
func textFieldDidChangeCommas(theTextField:UITextField) -> Void
{
if theTextField.text != nil {
var textFieldText = theTextField.text!.stringByReplacingOccurrencesOfString(",", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range: Range(start: theTextField.text!.startIndex, end: theTextField.text!.endIndex))
var formatter:NSNumberFormatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
if textFieldText != "" {
var formattedOutput = formatter.stringFromNumber(Int(textFieldText)!)
costField.text = formattedOutput
}
}
}

Resources