I've got a struct, which contains a static variable called userProfileImage, this struct is in a view controller called UserProfilePage.swift, here is the code:
struct UserProfile {
static let userProfileImage = UIImageView(image: #imageLiteral(resourceName: "profilePicture"))
}
class UserProfilePage: UIViewController {
// Some code that sets the userProfileImage to another image
}
The following code is in another swift file that has a struct called Downloads:
struct Downloads {
guard let profilePicURL = URL(string: profilePictureString) else {
UserProfile.userProfileImage.image = UIImage(named: "profilePicture")
print("Profile picture set to default profile picture")
return
}
// Some code
}
When profilePicURL is not empty, some code gets executed, but when it is empty (equal to ""), the code inside the else block gets executed. The problem is that the profile picture doesn't change, it just executes the print statement inside the else block. Does anyone know what's wrong with my code?
First of all, you have to change your userProfileImage. This Should be a var instead of **static let.
You can use if let statement with an async call in your code. Please try the following code.
let profilePictureString = "http://SOME URl STRING.."
if let profilePicURL = URL(string: profilePictureString){
// Plcae Your Network Code Here.
} else {
DispatchQueue.main.async {
UserProfile.userProfileImage.image = UIImage(named: "profilePicture")
print("Profile picture set to default profile picture")
}
}
You can call the setNeedsDisplay() for update the imageview
DispatchQueue.main.async {
UserProfile.userProfileImage.image = UIImage(named: "profilePicture")
UserProfile.userProfileImage.setNeedsDisplay()
}
use image literal
struct Downloads {
guard let profilePicURL = URL(string: profilePictureString) else {
UserProfile.userProfileImage.image = imageLiteral(resourceName: "profilePicture")
print("Profile picture set to default profile picture")
return
}
// Some code
}
Related
I followed this guide on how to setup a SLComposeViewController, and it includes on how to set up configuration items.
I'm pulling from a MongoDB database to get the most recently modified item. Here is my configurationItems():
override func configurationItems() -> [Any]! {
let configurationItems = [editConfigurationItem]
return configurationItems
}
and here is my editConfigurationItem variable:
lazy var editConfigurationItem: SLComposeSheetConfigurationItem = {
func getFirstCategory(completion: #escaping(String) -> ()) {
DispatchQueue.main.async {
let email: String = customKeychainWrapperInstance.string(forKey: "email") ?? ""
let password: String = customKeychainWrapperInstance.string(forKey: "password") ?? ""
app.login(credentials: Credentials.emailPassword(email: email, password: password)) { (maybeUser, error) in
DispatchQueue.main.sync {
guard error == nil else {
print("Login failed: \(error!)");
return
}
guard let _ = maybeUser else {
fatalError("Invalid user object?")
}
print("Login succeeded!");
}
let user = app.currentUser!
let configuration = user.configuration(partitionValue: user.id)
let predata = try! Realm(configuration: configuration)
let unsortedData = predata.objects(Tiktoks.self)
let data = unsortedData.sorted(byKeyPath: "date", ascending: false)
let firstCategory = data[0].category
let firstCategoryId = data[0]._id
print(firstCategory)
print(firstCategoryId)
self.selectedId = firstCategoryId
completion(firstCategory)
}
}
print("done")
}
let item = SLComposeSheetConfigurationItem()!
item.title = "collection"
item.valuePending = true
getFirstCategory() { (firstCategory) in
item.valuePending = false
print("completed")
item.value = firstCategory // Using self as the closure is running in background
}
item.tapHandler = self.editConfigurationItemTapped
return item
}()
(Sorry for the messiness of the code, I'm new to Swift)
So far it works, but the item.value variable doesn't get updated in the UI. It "infinitely loads" until you click on the configuration item. When the configuration item is tapped to go to another view though, the actual variable from the database shows for a split second before showing the next view. When you go back from that other view, the actual variable is there.
It looks like to me that the configuration item isn't updating. I see that there is a reloadConfigurationItems(), but by putting that in my editConfigurationItem will cause a loop I would think (and it also errors out too). The documentation even says:
In particular, you don’t need to call this method after you change a configuration item property, because the SLComposeServiceViewController base class automatically detects and responds to such changes.
but it looks like it's not detecting the changes.
Is there a way to refresh item.value and item.valuePending?
i'm trying to run a function inside a body. i'm not familiar how functions work in swiftUI.
here's the code below.
struct HomeView: View {
func getDirectory() -> String{
let fm = FileManager.default
let path = Bundle.main.resourcePath!
do {
let items = try fm.contentsOfDirectory(atPath: path)
for item in items {
print("Found \(item)")
}
} catch {
// failed to read directory – bad permissions, perhaps?
}
return path
}
let documentURL = Bundle.main.url(forResource: resourceURL, withExtension: "pdf")!
var body: some View {
let path = getDirectory()
print(path)
}
}
i'm getting an error saying.
''Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type''
how can i make this work?
I can't tell what you're trying to get from this document, but to answer your question directly, you need to provide a View within the body, not a String. You can add a Text that accepts a String parameter:
var body: some View {
Text(getDirectory())
}
var body: some View {
let noView: EmptyView = {
/*
Do what you want here
*/
return EmptyView()
}()
noView
}
I am attempting to execute code if an image exist.
The issue is I am unable to capture the state of empty image call.
The result is I get an empty image, but would rather put a placeholder image if possible.
func procImage(inName: String) {
switch (inName) {
case inName:
imageName = inName.lowercased()
default:
imageName = "blank"
}
}
This check is easy but you need to be sure that default image always exists.
func getSafeImage(named: String) -> Image {
let uiImage = (UIImage(named: named) ?? UIImage(named: "Default.png"))!
return Image(uiImage: uiImage)
}
Try this code:
func procImage(inName: String) -> UIImage {
if let confirmedImage = UIImage(named: inName) {
return confirmedImage
} else {
return UIImage(named: "Default_Image.png")!
}
}
Thanks all for contributing.
The solutions on offer did not quite work in my case except for Moreno's solution, but offered a path to my solution.
I did not need to store the result of the check, but just validate the existence of the file.
So this is what I came up with which worked.
This may not be the optimal solution, so improved code will be welcomed.
func procImage(inName: String) {
let imageConvertToLowercase = inName.lowercased()
if getMember.firstName.lowercased() == imageConvertToLowercase {
if (UIImage(named: imageConvertToLowercase) != nil) {
imageName = imageConvertToLowercase
} else {
imageName = "blank"
}
}
}
Hi I'm a newbie developer from Taiwan.
I have started to use firebase(ios) storage for my app and I want to use ImageSliderShow to make a image slider view. After I got the image URL from firebase. I appended the url string into array then I ran the app. The image slider view works fine but the new image just showing nothing. Then I printed the url String before and after I appended into the array. It gave me two different string. Here is my code.
override func viewDidLoad() {
super.viewDidLoad()
let URLString = loadURL()
URLString.getURL(){
(result:String) in
self.ImageSliderView.backgroundColor = UIColor.white
self.ImageSliderView.slideshowInterval = 5.0
self.ImageSliderView.pageControlPosition = PageControlPosition.insideScrollView
self.ImageSliderView.pageControl.currentPageIndicatorTintColor = UIColor.lightGray
self.ImageSliderView.pageControl.pageIndicatorTintColor = UIColor.black
self.ImageSliderView.contentScaleMode = UIViewContentMode.scaleAspectFill
self.ImageSliderView.activityIndicator = DefaultActivityIndicator()
self.ImageSliderView.currentPageChanged = { page in
print("current page:", page)
}
print("Result: \(result)") ////print the result string before appended into array.
self.kingfisherSource.append(KingfisherSource(urlString: String(result))!)
print("alamoArray3: \(self.kingfisherSource[3].url)") ////print the result string after appended into array.
self.ImageSliderView.setImageInputs(self.kingfisherSource)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(ResultViewController.didTap))
self.ImageSliderView.addGestureRecognizer(recognizer)
}
}
func didTap() {
let fullScreenController = ImageSliderView.presentFullScreenController(from: self)
// set the activity indicator for full screen controller (skipping the line will show no activity indicator)
fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
}
getURL function:
class loadURL {
let storage = Storage.storage(url: "my-firebase-storage-bucket")
func getURL(completion:#escaping (_ result:String)->Void) {
self.storage.reference().child("images/breakfast/1/1.jpg").downloadURL { url, error in
if error != nil {
print("Firebase Image URL error: \(String(describing: error))")
} else {
print("Firebase Image URL: \(String(describing: url!))")
completion("\(String(describing: url))")
}
}
}
The output:
Firebase Image URL: https://firebasestorage.googleapis.com/v0/b/my-firebase-storage-bucket/o/images%2Fbreakfast%2F1%2F1.jpg?alt=media&token=15ee8094-ac50-4e93-adc0-200793181bfc
Result: Optional(https://firebasestorage.googleapis.com/v0/b/my-firebase-storage-bucket/o/images%2Fbreakfast%2F1%2F1.jpg?alt=media&token=15ee8094-ac50-4e93-adc0-200793181bfc)
alamoArray3: Optional(https://firebasestorage.googleapis.com/v0/b/my-firebase-storage-bucket/o/images%2Fbreakfast%2F1%2F1.jpg?alt=m ... 3181bfc)
The 3rd output just weird... Is it possible be an encoding issue?
And I apology about my bad English.
Finally I just figure it out. I let the type of result as URL and then it just works perfectly.
I have a Core Data entity which has logo as one of its attributes - I need to check the count of logo, so I can properly set an image view in the cell (i.e. avoid a crash when a new company is added and doesn't have a logo). With a hardcoded array of, say, logos, it's as simple as logos.count, but I'm not sure how to perform the same check on a Core Data entity. What's the best way of doing this?
DispatchQueue.main.async {
if /*What to count?*/.count >= indexPath.row + 1 {
cell.logoView.image = UIImage(named: (company.value(forKey: "logo") as? String)!)
} else {
cell.logoView.image = UIImage(named: "noImage")
}
}
Based on what I can see from your current setup, the following should be fine:
DispatchQueue.main.async {
if let logo = company.value(forKey: "logo") as? String {
cell.logoView.image = UIImage(named: logo)
} else {
cell.logoView.image = UIImage(named: "noImage")
}
}
Let me know if this makes sense.