#IBOutlet var items: [UIButton]
#IBAction func itemsHidden(sender: UIButton) {
sender.hidden = true
items.removeAtIndex(sender)
}
Hello.
For example, i have array of items.
The code has the error: "Cannot invoke 'removeAtIndex' with an argument list of type (UIButton)".
What i need to do, that "removeAtIndex" works?
Thanks...
A removeAtIndex method expects to get an index as a parameter.
If you want to remove an object use func removeObject(_ anObject: AnyObject)
EDIT
There's no removeObject in a swift's array (only in NSMutableArray).
In order to remove an element, you need to figure out it's index first:
if let index = find(items, sender) {
items.removeAtIndex(index)
}
You don't tell us the class of your items object.
I assume it's an Array. If not, please let us know.
As Artem points out in his answer, removeAtIndex takes an integer index and remove the object at that index. The index must be between zero and array.count-1
There is no removeObject(:) method for Swift Array objects because Arrays can contain the same entry at more than one index. You could use the NSArray method indexOfObject(:) to find the index of the first instance of your object, and then removeAtIndex.
If you're using Swift 2, you could use the indexOf(:) method, passing in a closure to detect the same object:
//First look for first occurrence of the button in the array.
//Use === to match the same object, since UIButton is not comparable
let indexOfButton = items.indexOf{$0 === sender}
//Use optional binding to unwrap the optional indexOfButton
if let indexOfButton = indexOfButton
{
items.removeAtIndex(indexOfButton)
}
else
{
print("The button was not in the array 'items'.");
}
(I'm still getting used to reading Swift function definitions that include optionals and reference protocols like Generator so the syntax of the above may not be perfect.)
Related
I am building a Password Generator app, and I want to add the feature that the user can choose between generating a password with symbols in it such as: "!", "#", "&", ect. I want to do that with a UISwitch.
The problem is that I have an array of strings inside of a function (Inside the function I have all the code the make the generator work). Just like showed in the following picture:
And I have an IBAction of UISwitch, I tried appending a string with an if statement. Just like in the following screenshot:
But it just does not work.
I am new to swift so could someone help me with this problem? Thanks!
Couple of things. First, your words array is defined inside the generatePassword method. So it can only be used within that method. That's why you're getting the error when trying to access it from another method (switchSymbols).
To fix that, declare your words array as a class member.
class ViewController: UIViewController {
var words = ["A", "B", "C", "D"]
#IBAction func switchSymbols(_ sender: UISwitch) {
if sender.isOn {
words.append(contentsOf: ["!", "#", "$", "&"])
}
print(words)
}
}
Now every method within this view controller can access that array.
Second, notice how I changed the words array to a var from a let. let means it's a constant. Member declared as let cannot be changed after later. So you won't be able to append elements to it. When you define it as a var (variable), you can.
Third, see that I'm using the append(contentsOf:). The append(_:) method only adds a single element to an array. But in your code, you're adding another array directly to the words array. To add contents of one array to another array, you use the append(contentsOf:) method.
I have in in my app an function. Is there a way to transfer it to other Viewcontroller? if I use UserDefaults.standard.set(function(), forKey: "function")
I don't know how to load it, because
let function() = UserDefaults.standard.object(forKey: "function") as? CGFunction
doesn't work.
Thanks for answers!
Passing and returning functions
The following function is returning another function as its result which can be later assigned to a variable and called.
func jediTrainer () -> ((String, Int) -> String) {
func train(name: String, times: Int) -> (String) {
return "\(name) has been trained in the Force \(times) times"
}
return train
}
let train = jediTrainer()
train("Obi Wan", 3)
Yes, Swift allows you to pass functions or closures to other objects, since functions and closures are themselves first class objects.
However, you cannot save a function or closure to UserDefaults. To the best of my knowledge there is no way to serialize functions or closures, and in any case they certainly are not one of the very small list of types that can be saved to UserDefaults. (Known as "property list objects" since the same small set of types can be store to both property lists and to UserDefaults.)
Why do you want to pass a function to another view controller?
In Swift, functions are Closures. You can simply pass closures in code.
Class A {
var someFunction: (Int) -> String
init(f: (Int) -> String) {
someFunction = f
}
}
func f2(a: Int) -> String {
return "Value is: \(a)"
}
let AInstance = A(f: f2)
print(AInstance.someFunction(5)) // prints "Value is: 5"
or specific someFunction as optional like var someFunction: ((Int) -> String)! and set it later in code.
I'm going to answer your initial question:
I have in in my app an function. Is there a way to transfer it to other Viewcontroller?
Yes, there is a way: use your segue rather than trying to store the function in userDefaults.
1) Make sure that the destination view controller has an instance variable that can hold your function. (Note that in Swift 4, you'll have to make sure you either set a default value for that variable, or create a custom initializer to ensure the variable is given a value on initialization.)
2) In the first view controller, wherever you handle your segue, instantiate your destination view controller. Then set the variable to your function. (You can do this, for example, in an override of the prepare(for segue: UIStoryboardSegue, sender: Any?) method.)
I want to remove element of custom type value from an array.
I want to pass a variant instance to function to remove it from array, I don't want to use removeAtIndex().
var favoriteVariants: [Variant]
func removeVariant(variant: Variant)
{
}
If Variant is Equatable and you only want to remove the first one that matches:
if let idx = favoriteVariants.indexOf(variant) {
favoriteVariants.removeAtIndex(idx)
}
If it isn’t Equatable and you have some other matching criteria to find just one to remove:
let idx = favoriteVariants.indexOf {
// match $0 to variant
}
if let idx = idx {
favoriteVariants.removeAtIndex(idx)
}
(these are assuming Swift 2.0 – if 1.2, it’s find(favoriteVariants, variant) instead of indexOf, and there isn’t a version that takes a closure, though it’s not too hard to write one)
If there are multiple ones you want to remove in one go:
favoriteVariants = favoriteVariants.filter {
// criteria to _keep_ any given favorite
}
All of these could be wrapped in extensions if what you want to do is general enough to justify it.
ok so I am trying to return nil if a certain type is passed into my function. In this case im passing in an instance of my class "BlogPost" and a type within this blogpost. I also have an array called "types" and I have assigned the variable Videos to the last index of that array. If this type is passed into my function I would like to return nil (so assuming im going to need an optional here for returning a possible nil) this is what I have so far :-
so all in all I need to pass in an instance of my blog post but always return nil if a certain type is passed in. Hope this makes sense
Update:
The types array is defined as follows:
let types : [String] = ["technology", "Fashion", "Animals"]
this is the array I am referring to in the function. Basically if that last entry of the array is entered into the function I need to return nil
sure this is blogpost it does actually have an empty string for type
great so im getting there what Ive done now is change the blogpost.type to choose one at random. So now if the specfic type is chosen from this array how would I do that still getting an error. This is what I have updated to
so now all I need to do is access the 2 type in that array and if I do access it return nil. Any thoughts on that? so to drag it on thanks
I don't think you can. You can create failable initialisers which does what you need but you cannot use it with normal function.
The best solution for you would be return optional Int or String and when you call the function just check the result for nil and do what you need to do, otherwise ignore it:
func randomViews(blog : BlogPost.Type) -> Int? {
case 10:
return nil
case 10, 20 :
return 0
default:
random
}
if (randomViews(parameter) == nil) {
//function returned nil
}
You have displayed error because you compare optional blog to Videos, you have to unwrap it first, for example if you are sure the blog has always have a value use:
if blog! == Videos
if not sure is safer to use:
if let blg = blog {
if blg == Videos {
}
else {
// blog has not have a value
}
You are passing blog as a BlogPost.Type parameter. That is not correct. You should have either just passed it the String parameter, or you could pass it the BlogPost itself:
func randomViews(blog: BlogPost) {
let videos = types[2]
if blog.type == videos {
// do whatever you want
}
// carry on
}
Unrelated to your question at hand, but notice that I use let instead of var when defining videos. Always use let if the value will not (and cannot) change.
Also note that I use lowercase letter v in videos, because Cocoa naming conventions dictate that variables generally start with lowercase letters, whereas types, classes, structs, and enums generally start with uppercase letters.
I'm writing a new subclass of UIView using swift. I want to have an array of views, and I want to instantiate them in the initial declaration, for clarity.
If this was an Int array, I could do something like this:
let values: [Int] = (0...4).map() { $0 }
and so I'm trying to come up with some sort of similarly swifty one-liner that will create an array of UIButtons, instead of Ints.
my first thought was (0...4).map() { UIButton.buttonWithType(.Custom) } but if I do this (or if I replace the UIButton code with, say NSObject()) I get an error saying that "'Transition' does not have a member named 'map'". I can, say, do map() { "\($0)" } and get an array of strings.
My next thought was just to get an array of ints first, and then use map on those to return buttons, like:
let values: [UIButton] = (0...4)
.map() { $0 }
.map() { UIButton.buttonWithType(.Custom) }
but this gives me the same error. What am I doing wrong, here?
Okay, the solution came to me pretty quickly: I guess I can't quietly ignore the variable of the closure I'm passing in to the map function; I need to ignore it explicitly. So to get my array of 4 buttons, I can use an _ in the map function, like this:
var buttons = (0...4).map() {_ in UIButton.buttonWithType(.Custom) }
or what I actually ended up using:
lazy var buttons: [UIButton] = (0...4).map() { _ in
let button = UIButton.buttonWithType(.Custom) as UIButton
self.addSubview(button)
return button
}