I want to save some values in UserDefaults. And I am using this code to save
func SaveSettings(){
let def = UserDefaults.standard
def.set("test", forKey: "Value1")
def.set(myString, forKey: "Value2") //value: test1
def.set(myInt, forKey: "Value3") //value: 25
def.set(myInt64, forKey: "Value4") //value: 103254
def.synchronize() //I've tried to remove this line
}
After saving I use this code to control if my values are saved in UserDefaults or not
for (key, value) in UserDefaults.standard.dictionaryRepresentation() {
print("\(key) = \(value) \n")
}
And see this result
{
Value1 = test
Value2 = test1
Value3 = 25
Value4 = 103254
}
There isn't any problem untill now. But After I restart the app and look at the values in UserDefaults I see this result
{
Value1 = test
Value2 =
}
As you see Value3ad Value4 are missing. However Value2 and Value1 stays. but Value2's value is missing
I've found the problem.
SaveSettings() func have called when myInt and myInt64's values are nil and myString's value is empty. Somehow Value3 and Value4 are deleted here. I guess this happen becaues of their value is nil. But I am not sure this is exact reason.
When you run your app, string value which u have set in the Value1 will get saved, but the string objects are not getting any values when the app initially runs. So you need to check myInt, myString, myInt64 are not getting nil before saving into UserDefaults.standard.
Related
I'm trying to understand how to code something along the lines of "NOT IN the LIST" type of logic in SAS.
I figured I could do "NOT" + "IN" as something like below.
Data work.OUT;
Set work.IN;
If VAR=1 then OUTPUT=1;
else if VAR=2 then OUTPUT=2;
else if VAR NOT in (1,2) then OUTPUT=3;
else OUTPUT=4;
run;
When I export the dataset all I see is OUTPUT=3 for all records. So something is happening in the derivation and it's transforming all VAR values into OUTPUT 3 values for some reason. Even though I know for a fact that other values exist in the VAR.
I don't understand what the problem is? Can we not combine NOT+IN operators? Alternatively, do you have any other ways of coding this type of logic in SAS? I rather not code each bit of code since I have more than 300 unique values for VAR
Welcome to Stack Overflow Alejandro. Your code assigns values 1 2 or 3 depending on what values are in the variable called var:
data in;
do var = 1 to 5;
output;
end;
run;
Data work.OUT;
set work.IN;
If VAR=1 then OUTPUT=1;
else if VAR=2 then OUTPUT=2;
else if VAR NOT in (1,2) then OUTPUT=3;
else OUTPUT=4;
run;
Your code says check for var = 1 then check for var = 2 and then check if it is not 1 or 2. The final else is never checked because a var will be 1 or 2 or not 1 or 2.
If you have a pile of if checks, you can use a select/when/otherwise/end block. It will check a series of rules (in the order you type them) and then will do something based on whichever rule is true first.
data out;
set in;
select;
when(var = 1) output = 1;
when(var = 2) output = 2;
when(var < 5) output = 3;
when(.) output = -9999999;
otherwise output = 42;
end;
run;
I hope that helps. If not please send up another flare.
I am trying to automatically RegExp(extract) the digits(AREA number) in Column 3 combined with the Text 'A' to append in Column 1 Date INDEX.
The problem is I'm not yet familiar in using google sheets app-scripts.
Tried looking for solutions with similar situation as me, but to no avail.
I don't know to put VBA to app-scripts.
Tried using some codes.
I still can't seem to make it work.
Can anyone point me in the right direction?
Thank you if you can help me out. Thanks.
EDIT:
The scenarios is in the office i cant make column for the formula.
It must be "behind the scene".
My googlesheets
//NOT WORKING code
function onEdit(e) {
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var regExp = new RegExp("\d*"); // Extract the digits
var dataIndex = regExp.exec(area)[1];
if(rg.columnStart==3) { // Observe column 3
var vA=rg.getValues();
for(var i=0;i<vA.length;i++){
if(vA[i][0]) {
sh.getRange(rg.rowStart + i,1).appendText((dataIndex) +'A'); // append to column 1 with 'A' and extracted digits
}
}
}
}
This answer extends your approach of using a script with an OnEdit trigger. But there are a number of differences between the two sets of code.
The most significant difference is that I have used the Javascript split method (var fields = value.split(' ');) to get distinct values from the data entry.
Most of the other differences are error checking:
if(rg.columnStart === 3 && area === "work") {: test for sheet="work" as well as an edit on Column C
var value = e.value.toUpperCase();: anticipate that the test might be in lower case.
if (fields.length !=2){: test that there are two elements in the data entry.
if (fields[0] != "AREA"){: test that the first elment of the entry is the word 'area'
if (num !=0 && numtype ==="number"){; test that the second element is a number, and that it is NOT zero.
if (colA.length !=0){: test that Column A is not empty
var newColA = colA+"A"+num;: construct the new value for Column A by using unary operator '+'.
function onEdit(e){
// so5911459101
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
//Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value.toUpperCase();
//Logger.log("DEBUG: the value = "+value+", length = "+value.length+", uppercase = "+value.toUpperCase());
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// Logger.log("DEBUG: number of fields = "+fields.length)
// test if there are two fields in the value
if (fields.length !=2){
// Logger.log("DEBUG: the value doesn't have two fields")
}
else{
// Logger.log("DEBUG: the value has two fields")
// test if the first field = 'AREA'
if (fields[0] != "AREA"){
// Logger.log("DEBUG: do nothing because the value doesn't include area")
}
else{
// Logger.log("DEBUG: do something because the value does include area")
// get the second field - it should be a value
var num = fields[1];
num =+num
var numtype = typeof num;
// Logger.log("DEBUG: num= "+num+" type = "+numtype); //number
// test type of second field
if (num !=0 && numtype ==="number"){
// Logger.log("DEBUG: the second field IS a number")
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// test if Column A is empty
if (colA.length !=0){
var newColA = colA+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
// Logger.log("DEBUG: do nothing because column A is empty")
}
}
else{
// Logger.log("DEBUG: the second field isn't a number")
}
}
}
}
else{
//Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}
REVISION
If the value in Column C is sourced from data validation, then no need for and testing except that the edit was in Column C and the sheet = "work".
Included two additional lines of code:
var colAfields = colA.split('-');
var colAdate = colAfields[0];
This has the effect of excluding any existing characters after the hyphen, and re-establishing the hyphen, row number plus "A" and the AREA numeral.
function onEdit(e){
// so5911459101 revised
// only one test - check for ColumnC and sheet="work"
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value
//Logger.log("DEBUG: the value = "+value+", length = "+value.length);
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// get the second field - it should be a value
var num = fields[1];
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// use Javascript split on Column A in case of existing value
var colAfields = colA.split('-');
var colAdate = colAfields[0];
// build new value
var newColA = colAdate+"-"+row+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}
I am using a web service to get information. When said info is returned, I convert the data received from jason to a dict.
When Dumping dict object, some of the items arrive like this:
▿ (2 elements)
- key: "street1"
- value: <null> #4
How would i go about reading this data and knowing that the value is NULL
I have tried the following:
let street1:String = dict?["street1"] as! String
This fails with: Could not cast value of type 'NSNull' (0x10fbf7918) to 'NSString' (0x10f202c60).
The data could have a String value. So I tried:
let street1:Any = dict?["street1"] as Any
When I print street1 thus
street1: Optional()
I get the following
street1: Optional()
So my question is:
How would i go about reading this data and knowing that the value is null.
You can use if let for this type of nil check.
Try this instead:
if let street1 = dict?["street1"] as? String {
// If this succeeds then you can use street1 in here
print(street1)
}
Update:
var t_street1 = ""
if let street1 = dict?["street1"] as? String {
t_street1 = street1
}
No need for the else t_street1 is automatically empty since you assign it empty.
I have an issue with a Crystal Report that I'm creating. I am using fields from a database and am pulling in the result value where the analysis field is equal to certain values.
In the condition the first check looks at the analysis field and checks if its equal to "Conf". The result for this is "<10"
The second check looks at the analysis field and checks if its equal to "Original". The result for this is "20".
I want the results to display in the order above however with the following basic logic it returns the result of 20.
if analysis = "conf" then result
else if analysis = "Original" then result
I was having this issue with multiple records however solved it by converting both results to numbers (toNumber(Result)). However this record has the less than symbol contained within the field value which causes the conf result to "be skipped" and will display the original result instead. I've tried a few things without success. Here is the code for the condition of where I'm at below. I fell this is way to complex logic but I've just added to it as I've had ideas and it shows what I've tried.
if {UNITS} = "CFU_G" then
if {ANALYSIS} = "CONF" and
{RESULT}="" or
{RESULT} = "0" then 0
else if {ANALYSIS} = "CONF"
then if isNumeric({RESULT}) then
tonumber({RESULT}) else
tonumber(Replace ({RESULT}, "<", ""))
else
if {UNITS} = "CFU_G" then
if {ANALYSIS} = "Original" and
{RESULT}="" or
{RESULT} = "0" then 0
else if {ANALYSIS} = "Original"
then if isNumeric({RESULT}) then
tonumber({RESULT}) else
tonumber(Replace ({RESULT}, "<", ""))
Thanks,
Tom
This was the solution I came up with.
Field 1
whileprintingrecords;
stringvar vResult := "";
Field 2
whileprintingrecords;
stringvar vResult;
vResult := if {RESULT.UNITS} = "CFU_G"
and {RESULT.ANALYSIS} = "CRA_LIS_ENU_CONF_MPCRAM29"
then {RESULT.FORMATTED_ENTRY}
else if {RESULT.ANALYSIS} = "CRA_LIST_ENU_MPCRAM29"
and {RESULT.UNITS} = "CFU_G"
and vResult = ""
then {RESULT.FORMATTED_ENTRY}
Field 3
whileprintingrecords;
stringvar vResult;
vResult;
I have the following code:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.decimal
numberFormatter.maximumFractionDigits = 2
let formattedNumber = numberFormatter.string(from: NSNumber(value: rawValue))
currentLogBF.text = "\(formattedNumber) BF"
In the above example, rawValue is a Double that is calculated when all of the input fields have values in them.
currentLogBF is a label in my View.
Whenever a calculation is completed, the label displays something like this:
Optional("12,307.01") BF
How do I get rid of the "Optional()" piece, so it just displays this:
12,307.01 BF
Any ideas what I am doing wrong here?
The function numberFormatter.string(from: NSNumber) will return you a String Optional (String?) instead of String.
You will need to unwrap it first like this
if let formattedNumber = numberFormatter.string(from: NSNumber(value: rawValue)) {
currentLogBF.text = "\(formattedNumber) BF"
} else {
Log.warn("Failed to format number!")
}
And as bonus, use String(format: "%# BF", formattedNumber) rather than "\(formattedNumber) BF" when dealing with optional.
String(format:) will give you compile error when you try to pass optional value as an argument
unwrapping an optional value
let formattedNumber:String? = numberFormatter.string(from: NSNumber(value: rawValue))
currentLogBF.text = "\(formattedNumber!) BF" //optional string. This will result in nil while unwrapping an optional value if value is not initialized or if initialized to nil.
currentLogBF.text = "\(formattedNumber) BF" //Optional("optional string") //nil values are handled in this statement