Cannot convert value of type 'UIImage' to expected argument type 'String'
I am trying to create a book, and if I type in the name of the picture I want in the UIImageView constructor which is "cup", my program executes correctly and displays the same picture on every page. If I try and do "imageNames[element]" to get all my pictures displayed depending on page within my for loop it says it can not convert UIImage to String
var imageNames: [UIImage] = [
UIImage(named: "open")!,
UIImage(named: "cup")!
]
for element in 0 ..< imageNames.count {
let vc = UIViewController()
vc.view.backgroundColor = randomColor()
//Where error is occurring!
let imageView = UIImageView(image: UIImage(named:
imageNames[element]))
vc.view.addSubview(imageView)
}
I would think that imageNames[element] would give me the String value in the array.
My goal is that when I open the book.... "open" picture is on the first page, and "cup" picture is on the second page.
Just use an array of strings rather than images
let imageNames = ["open", "cup"]
for imageName in imageNames { // no reason for an index based loop
let vc = UIViewController()
vc.view.backgroundColor = randomColor()
let imageView = UIImageView(image: UIImage(named: imageName))
vc.view.addSubview(imageView)
}
Or if you really want an array of images
let images = [
UIImage(named: "open")!,
UIImage(named: "cup")!
]
for image in images { // no reason for an index based loop
let vc = UIViewController()
vc.view.backgroundColor = randomColor()
let imageView = UIImageView(image: image)
vc.view.addSubview(imageView)
}
Related
My swift codes goal is to create a array of images appended from a tableview cell. The code works however if the image is repeated twice. Right now sc.jpg is repeated twice in the array somepics when the code is appended. What prints out is gwen.jpg, kids.jgp, and sc.jpg only once. I want sc.jpg to appear twice in the array just like how it is in array somepics.
var arrayThatStartsEmpty = [UIImage]()
var somePics: [UIImage] = [UIImage(named: "gwen.jpg")!, UIImage(named: "kids.jpg")!, UIImage(named: "sc.jpg")!, UIImage(named: "sc.jpg")!]
#objc func collect(){
let collect = (0..<arr.count).compactMap { (theTable.cellForRow(at: IndexPath(row: $0, section: 0)) as? customtv)?.pic }
let arrayValues2 = collect.compactMap { $0.image }
arrayThatStartsEmpty.append(contentsOf: arrayValues2)
print(arrayValues2)
}
I made some changes on your collect() method. You can give it a try
#objc func collect(){
let collect = arr.enumerated().compactMap { (index, _) in
(theTable.cellForRow(at: IndexPath(row: index, section: 0)) as? customtv)?.pic }
let arrayValues2 = collect.compactMap { $0.image }
arrayThatStartsEmpty.append(contentsOf: arrayValues2)
print(arrayValues2)
}
I'm new to Swift and got stuck on something I've been experimenting.
Big picture:
I want to set up an app where I will have a set of images and when you press on an image it will produce a specific sound allocated to it.
Problem:
I have an array of images in the collectionView and was hoping that if I could automatically assign a tag to the images consecutively then I could line up the sounds according to the tag and link the sound to the image that way.
I have been playing around with the tag assignments for a few hours now and can't seem to be able to do it. The best I've got is set out below, could anyone help?
import UIKit
import AVFoundation
class basicVocabViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate {
#IBOutlet weak var collectionView: UICollectionView!
var audioPlayer:AVAudioPlayer?
let cards = ["1", "2", "3", "4"]
let cardImages: [UIImage] = [
UIImage(named: "1")!,
UIImage(named: "2")!,
UIImage(named: "3")!,
UIImage(named: "4")!,
]
// Assign tag to each UIImage
var cardImages.tag = 0
var currentTag = 0
for counter in cardImages {
let firstImage.tag = currentTag
currentTag += 1
}
}
You can only assign tag on a UIView. So, use UIImageView to set a tag. Just use a loop for the array of UIImageView as follows:
let cardImageViews = [UIImageView]()
for (index, imageView) in cardImageViews.enumerated() {
imageView.tag = index
}
This is my code in swift 4 xcode. i have problems with my code. I can't show my array, with images on the simulator what things I'm doing wrong?
im a beginner in swift. and i have tried too look up how you write an array with images with four loop but the simulator docent show
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let img : UIImage = UIImage(named: "owl")!
let imageView = UIImageView(image: img )
self.view.addSubview(imageView)
// var images = Array<UIImage>()
//images.append(UIImage(named: "lion")!,
let ImgArray = ["lion.png","wolf.png","snake.png"]
var images = [UIImage]()
for i in 0..<ImgArray.count
{
images.append(UIImage(named: ImgArray[i])!)
}
let imageView2 = UIImageView(image: img )
self.view.addSubview(imageView2)
}
}
As explained by #Robert, instead of using the index of the array, you can use a for loop this way :
let imagesNames = ["img1.png", "img2.png", "img3.png"]
for imageName in imagesNames {
let image = UIImage(named: imageName)
images.append(image)
}
You can also use map to directly transform your array of images names to an array of images :
let imagesNames = ["img1.png", "img2.png", "img3.png"]
let images = imagesNames.map { UIImage(named: $0) }
where 0$ is your imageName.
In my first vc (ViewController) I have button with action performSegue. In override func prepare(for segue:) I want to send data to another view controller.
This is my code:
if segue.identifier == "nextVC" {
let data1 = ["TITLE", "TITLE2"]
let data2 = ["DESCRIPTION", "DESCRIPTION 2", "DESCRIPTION 3"]
let destination = segue.destination as! DestinationController
destination.cellString1 = data1
destination.cellString2 = data2
destination.array = array
In my second vc (DestinationController) I have variable cellString1, cellString2 and array like below:
var array: [String] = []
var cellString1: [String] = []
var cellString2: [String] = []
In array I send to second vc id of tableView cell in first vc like below:
["0", "1", "1", "0", "1"]
In second vc I have tableView too with code (in tableview(cellForRowAt:))like below:
if array[indexPath.row] == "0" {
cell.textLabel?.text = cellString1[indexPath.row]
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 16)
cell.backgroundColor = UIColor.black
return cell
} else if array[indexPath.row] == "1" {
cell2.textLabel?.text = cellString2[indexPath.row]
cell2.textLabel?.textColor = UIColor.gray
cell2.textLabel?.font = UIFont.systemFont(ofSize: 12)
cell2.backgroundColor = UIColor.red
return cell2
where I want to detect if array in cell have value (0 or 1) then label of cell take value from cellString1 or cellString2 and show text of this label. When I delete cells textLabel configuration, colors of cells background are correct (black, red, red, black, red) however in full code I have error (Index out of range) in line cell.textLabel?.text = cellString1[indexPath.row].
Is possible to fix that?
This should be :
destination.cellString1 = data1
destination.cellString2 = data2
destination.array = array
let destination = segue.destination as! DestinationController
you should perform segue after destination.cellString1 = data1, destination.cellString2 = data2 and destination.array = array. Else these properties won't be assigned.
This is expected because the 3 arrays have different count , and sure indexPath will exceed for cellString1 as it contains 2 items , and second "0" of array is in index 3 which exceeds count of cellString1
You got 2 titles, 3 descriptions and 5 color flags. If you are using multiple arrays as data source you have to make sure that the number of items are always the same.
For example if you return array.count in numberOfRows then cellForRow is called 5 times. But there is no item at indexPath.row > 1 in cellString1 and indexPath.row > 2 in cellString2. This causes the out-of-range exception.
Basically you are strongly discouraged from using multiple arrays as data source. Don't do that.
Use a custom struct instead and rather than "0" and "1" strings use a Bool
struct Item {
var title : String
var description : String
var colorFlag : Bool
}
Then create Item instances with the appropriate data and pass one array.
I have an array of string which to convert to an array of images.
var inviteStatus = [Any]()
inviteStatus = ["accepted", "accepted", "pending", "pending"]
When the invite status is "accepted", I want it to be replaced with an image at that index. The desired result is this:
inviteStatus = [UIImage(named: "accepted.png"), UIImage(named: "accepted.png"), UIImage(named: "pending.png"),, UIImage(named: "pending.png")]
I tried with this following code but it's not working:
for (index, str) in self.arrayInviteStatus.enumerated() {
self.arrayInviteStatus[index] = str.replacingOccurrences(of: "accepted", with: UIImage(name: "accepted.png"))
self.arrayInviteStatus[index] = str.replacingOccurrences(of: "pending", with: UIImage(name: "pending"))
}
Thank you for your help.
Use map
let inviteStatusImages = inviteStatus.map{ UIImage(named: $0+".png") }
You are discouraged from using [Any]. Better use two separate arrays with distinct types.
I think map is definitely the way to go, but maybe consider using an enum, so you get a type safe way to distinguish between the two cases:
enum InviteStatus {
case accepted
case pending
}
Now you could have an Array of InviteStatus and combine map with pattern matching:
let inviteStatus: [InviteStatus] = [.accepted, .accepted, .pending, .pending]
func statusToImage(status: InviteStatus) -> UIImage {
switch status {
case let .accepted: return UIImage(named: "accepted.png")
case let .pending: return UIImage(named: "pending.png")
}
}
let imageArray = inviteStatus.map(statusToImage)
What this gives you is the ability to easily refactor without losing type safety. E.g. if you want to add another status case in the future like "declined", or something similar, you can add it to your enum and the switch-case pattern match will tell you at compile time that you'll have to add another case to it.
you can do like this
var inviteStatus: [String] = []
inviteStatus = ["accepted", "accepted", "pending", "pending"]
var imgArray: [UIImage] = []
imageArray = inviteStatus.map { UIImage(named: "\($0).png") }
You can try to create an integrate array and then pass the variables to the original array
var inviteStatus = [Any]()
inviteStatus = ["accepted", "accepted", "pending", "pending"]
//inviteStatus = [UIImage(named: "accepted.png"), UIImage(named: "accepted.png"), UIImage(named: "pending.png"),, UIImage(named: "pending.png")]
var newArray = [Any]()
for invStat in inviteStatus {
newArray.append(UIImage(named: "\(invStat).png"))
}
inviteStatus.removeAll()
for na in newArray{
inviteStatus.append(na)
}