Random Number Generator in url - ios

I currently have a random number generator in my url that is used to assign new numbers to the page parameter of the url. When I fetch a new image and print the url, it uses the same url. I do not know how to approach removing the existing random number in the url.
Here is my declaration:
public static var random = Int.random(in: 0..<450)
static let ImageURL = "https://api.unsplash.com/search/photos/?client_id=\(UnsplashClient.apiKey)&page=\(random))"

Do not use static for your array. Static variables only generated once. So it does not generate random numbers for you.
read this: When to use static constant and variable in Swift?

According to me, You have to create a array of numbers that contains integers from 0 to 450 like this var array = Array(0...450) and and then can select random number from that array using array.randomElement()!. And after selecting, remove that number from that array.

Since you're using a static property and it's value is not gonna change each time you call it, unless you update it manually. You can fix this issue by using static computed property whose value is computed everytime it's used.
public static var random: Int { .random(in: 0..<450) }
public static var ImageURL: String { "https://api.unsplash.com/search/photos/?client_id=\(UnsplashClient.apiKey)&page=\(random))" }
Or you can combine them as #leo has mentioned in the comments, if you don't have any other purpose for random, like this:
public static var imageURL: String { "https://api.unsplash.com/search/photos/?client_id=\(UnsplashClient.apiKey)&page=\(Int.random(in: 0..<450)))" }

Related

How to split this string in Dart? /data/data/com.example.trail/cache/IMG_1645484057312.png

I need to get the name of an image path, which is a String. How could i say programmatically in dart "when you find the first / from the right hand side split it, then give it to me"?
the string which i need to split is:
'/data/data/com.example.trail/cache/IMG_1645484057312.png'
You can use split like the #scott-deagan answer for it. But if you intend to support cross-platform path manipulation, you need to use path package.
Example:
import 'package:path/path.dart' as p;
void main() {
var filepath = '/data/data/com.example.trail/cache/IMG_1645484057312.png';
print(p.basename(filepath));
print(p.basenameWithoutExtension(filepath));
}
result:
IMG_1645484057312.png
IMG_1645484057312
void main() {
var someFile = '/data/data/com.example.trail/cache/IMG_1645484057312.png';
var fname = someFile.split('/').last;
var path = someFile.replaceAll("/$fname", '');
print(fname);
print(path);
}
Here is the way I recommend you to test
First, do the split on the original string by "/" splitter, then extract the last member of the list created by the splitter to get the name of the png file.
Second, for extracting the remaining string (i.e. the file path), use the substring method of the class string. just by subtracting the original string length from the last_member length in the previous portion, you are able to get the file path string.
Hope to be useful
Bests
void main() {
String a = '/data/data/com.example.trail/cache/IMG_1645484057312.png';
var splited_a = a.split('/');
var last_image_index = splited_a.last;
String remaining_string = a.substring(0, a.length - last_image_index.length);
print(remaining_string);
print(last_image_index);
}
result:
the result of path and file extraction from a string in dart

Dynamic Struct Variable Name

I define a struct as follows:
struct MyModel : Decodable {
var id : Int
var amount: Int
let myNewTableId : Int
let userId : Int
let myNewTable : MyNewTable
}
I then use this struct to convert JSON data into an object using JSONDecoder().decode.
The problem is that the myNewTable part of myNewTableId and myNewTable are based on an alias given to the SQL table they originate from. So if the alias is abc the fields should be abcId and abc and if its def it should be defId and def. I've saved this alias into a variable:
let MY_NEW_TABLE_ALIAS = "myNewT"
Is there a way to construct the variable names in the struct dynamically using MY_NEW_TABLE_ALIAS. Ideally, when the alias changes on the SQL side, I just want to update one variable, instead of having to update every single struct which uses that table.
The simple way is to convert the json first to a string and replace occurrences with the needed key / use CodingKeys and make the struct as it is , btw you can't have dynamic variable names

Get string non localized

I am trying to get string from string file called "Common.strings" that I have created to store some non translated strings like URLs and names.
So, to do that I created the a strings file called "Common":
I find the way using localizedString like below:
Bundle.main.localizedString(forKey: "api_url", value: "", table: "Common")
There are another way to do that ? The code that I am using is right ?
I am asking cause I don't want a "localized" string
Declare the constant values as such in code, there is no need to create a .strings file.
E.g. let urlString = "http://mywebsite.com"
You could also put it inside a struct to effectively namespace your constants:
struct Constants {
static let urlString = "http://www.mywebsite.com"
}
Giving you something like: let baseUrlString = Constants.urlString

Swift: Dictionary passed as parameter is always empty

I want to fill Dictionary via a method of which dictionary is one of the parameter. When I add a value to key, say 15, it always return 0 count when I try to access it second time with same key i.e. 15. Here's the code.
private static var showWidgetMap = Dictionary<Int, [BaseWidget]>()
private static var hideWidgetMap = Dictionary<Int, [BaseWidget]>()
static func initHandler()
{
let cloudWidget = CloudWidget()
cloudWidget.setType(CreatorConstants.CLOUD)
let property1 = [CreatorConstants.IMG_SRC: "cloud1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "450"]
cloudWidget.setPropery(property1)
addWidgetInLocalTimeList(15, widget: cloudWidget, delete: false)
let emojiWidget = CloudWidget()
emojiWidget.setType(CreatorConstants.EMOTICON)
let property2 = [CreatorConstants.IMG_SRC: "1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "550"]
emojiWidget.setPropery(property2)
addWidgetInLocalTimeList(15, widget: emojiWidget, delete: false)}
static func addWidgetInLocalTimeList(time_milisec: Int, widget: BaseWidget, delete: Bool)
{
if(delete)
{
checkAndAdd(hideWidgetMap, key: time_milisec, widget: widget);
}
else
{
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget);
}
}
private static func checkAndAdd(var map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
{
print("map count is")
print(map.count)
if var val = map[key]
{
val.append(widget);
}
else
{
var temp: [BaseWidget] = [];
temp.append(widget);
map[key] = temp
print(map.count)
}
}
print(map.count) always returns 0.
You need to understand the difference between value types and reference types.
Value type variables are just values. For example, an array is a value type. It is just a value of "a bunch of stuff" *. On the other hand, reference types are references to values. For example, when you create a UIViewController, that variable actually stores a reference to the actual UIviewController *.
Don't really understand? Then it's analogy time! The variables and constants you create are children. The things you put in variables and constants are balloons.
There are two types of children, one type (value types) likes to hold balloons directly in their hands. The other type (reference types) likes to hold balloons using a string **.
When you pass a child to a method, depending on what type of child he is, different things will happen:
A value type child holds the balloon in his hands, so tightly that the method parameter can't take it away from him. So what can it do? It creates a copy of it! It then takes the copy to the method implementation let it do its thing.
A reference type, however, holds balloons using a string. The method parameter will tie another string to the balloon so the implementation can access it using the string. As a result, no copies of the balloon are created.
So what are you doing wrong here?
Since swift dictionaries are value types, when you pass a dictionary to a method, as I said above, it creates a copy! In the implementation, you are actually editing a copy of the dictionary, not the original one. That's why the original dictionary still has a count of 0.
What can you do?
Instead of marking the parameter with var, which is a very bad practice btw, you mark it with inout!
private static func checkAndAdd(inout map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
The inout modifier basically says
Hey parameter, next time you see a value type, just get a string and tie it to the balloon that the child is holding.
There is also another thing that you should do. That is you should change the way you call your method.
Instead of
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget)
You write
checkAndAdd(&showWidgetMap, key: time_milisec, widget: widget)
And magically, it works!
Conclusion: Parameters are dumb. They aren't even smart enough to know when to tie a string. Be careful when you work with value types.
Footnotes * Assume it is not nil
** Not the String type, but an actual string.

Extra argument in call error mystery

I had some older Swift code that used to compile and work where I was using the .append to build out a data structure dynamically. After upgrading to a few compiler versions newer I am getting the dreaded "Extra Argument ' ' in call" error. I reduced the code down to this:
struct EHSearch {
let EHcategory : String = ""
let EHname : String = ""
}
var myEHSearch = [EHSearch]()
// Call to dynamically append the results
// Extra argument: 'EHcategory' in call
myEHSearch.append(EHSearch(EHcategory: "Food", EHname: "Joes Crab Shack"))
I can't see anything so far in searching on what has changed to cause this one so seeking guidance here.
Because you have let in your struct.
Define your structure like this:
struct EHSearch {
var EHcategory : String = ""
var EHname : String = ""
}
If you have constants in your struct, you can not provide them initial value while creating new structure instances. The automatically-generated member-wise initializer doesn't accept let members as parameters of the initializer of struct.
It depends on your intentions with the struct's properties. Do you want them to be mutable or not?
If yes, then #sasquatch's answer will do.
If not, then you need to ensure a value is assigned to them only once. As you already do that in the struct declaration (the default values), you can't assign new values to them. But being a struct, they don't need to have default values - moreover, struct automatically receive a memberwise initializer. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
So here is the variant for immutable properties:
struct EHSearch {
let EHcategory : String
let EHname : String
}
var myEHSearch = [EHSearch]()
// Call to dynamically append the results
// Extra argument: 'EHcategory' in call
myEHSearch.append(EHSearch(EHcategory: "Food", EHname: "Joes Crab Shack"))
The "Extra Argument" error you're seeing is because the compiler already has values for the properties so it doesn't expect any new ones. Here is the "middle" way - one property has a default value whilst the other doesn't - which should make it clearer:
struct EHSearch {
let EHcategory : String = ""
let EHname : String
}
var myEHSearch = [EHSearch]()
// Call to dynamically append the results
// Extra argument: 'EHcategory' in call
myEHSearch.append(EHSearch(EHname: "Joes Crab Shack"))

Resources