iOS 9: Restore default styling to UIAlertController after calling UICollectionViewCell.appearance() - uicollectionviewcell

Say I want to present a UIAlertController:
import UIKit
class ViewController: UIViewController {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(title: "Alert!", message: "Whoops.", preferredStyle: .Alert)
let dismiss = UIAlertAction(title: "Go back.", style: .Default) { (_) in }
alert.addAction(dismiss)
self.presentViewController(alert, animated: true, completion: nil)
}
}
Elsewhere in the app, I've got a UICollectionView, which I'm styling using UIAppearance in my AppDelegate (best to follow Mattt Thompson's advice):
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
UICollectionViewCell.appearance().backgroundColor = UIColor.blackColor()
return true
}
This turns the background of the UIAlertAction buttons black, which isn't what I intended.
I tried using the new appearanceWhenContainedInInstancesOfClasses functionality in iOS 9 to restore the default styling...
UICollectionViewCell.appearanceWhenContainedInInstancesOfClasses([UIAlertController.self]).backgroundColor = nil
...but this gives me an EXC_BAD_ACCESS error on that line.
How can I use UICollectionViewCell.appearance(), without disrupting my UIAlertController styling?

Related

Cannot retrieve data back to my app from Firebase

I hope the problem is explained well on the title but what I want to do is to write the message on my message app and want to retrieve it and write it on the app's message cell but nothing is seen. When I go to my firebase console I can see the messages there but not on app. I didn't attach anything about project but I don't know what to attach. but let me add my chatViewController at least .`import UIKit
import Firebase
class ChatViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var messageTextfield: UITextField!
let db = Firestore.firestore()
var messages: [Message] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
navigationItem.hidesBackButton = true
title = K.appName
tableView.register(UINib(nibName: K.cellNibName, bundle: nil), forCellReuseIdentifier: K.cellIdentifier)
loadMessages()
}
func loadMessages() {
db.collection(K.FStore.collectionName)
.order(by: K.FStore.dateField)
.addSnapshotListener { (querySnapshot, error) in
self.messages = []
if let e = error {
print("There was an issue retrieving data from Firestore \(e)")
}else {
if let snapshotDocuments = querySnapshot?.documents {
for doc in snapshotDocuments {
let data = doc.data()
if let messageSender = data[K.FStore.senderField] as? String, let messageBody = data[K.FStore.bodyField] as? String {
let newMessage = Message(sender: messageSender, body: messageBody)
self.messages.append(newMessage)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
}
}
#IBAction func sendPressed(_ sender: UIButton) {
if let messageBody = messageTextfield.text, let messageSender = Auth.auth().currentUser?.email {
db.collection(K.FStore.collectionName).addDocument(data: [K.FStore.senderField: messageSender, K.FStore.bodyField: messageBody]) { (error) in
if let e = error {
print("There was an issue saving data to firestore \(e)")
} else {
print("successfully saved data.")
}
}
}
}
#IBAction func logOutPressed(_ sender: UIBarButtonItem) {
do {
try Auth.auth().signOut()
navigationController?.popToRootViewController(animated: true)
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
}
}
extension ChatViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! MessageCell
cell.label.text = messages[indexPath.row].body
return cell
}
}
`
And below is console output
'<FIRFirestore: 0x6000016d7040>
2022-10-17 17:55:19.817200+0300 Flash Chat iOS13[5876:41767] 10.0.0 - [FirebaseAnalytics][I-ACS023007] Analytics v.10.0.0 started
2022-10-17 17:55:19.817551+0300 Flash Chat iOS13[5876:41767] 10.0.0 - [FirebaseAnalytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see xxx
2022-10-17 17:55:19.824914+0300 Flash Chat iOS13[5876:41677] [Assert] UINavigationBar decoded as unlocked for UINavigationController, or navigationBar delegate set up incorrectly. Inconsistent configuration may cause problems. navigationController=<UINavigationController: 0x13984a200>, navigationBar=<UINavigationBar: 0x13950f870; frame = (0 48; 0 50); opaque = NO; autoresize = W; layer = <CALayer: 0x600000390980>> delegate=0x13984a200
2022-10-17 17:55:19.873401+0300 Flash Chat iOS13[5876:41763] 10.0.0 - [FirebaseAnalytics][I-ACS800023] No pending snapshot to activate. SDK name: app_measurement
2022-10-17 17:55:19.890442+0300 Flash Chat iOS13[5876:41765] 10.0.0 - [FirebaseAnalytics][I-ACS023012] Analytics collection enabled
2022-10-17 17:55:19.890731+0300 Flash Chat iOS13[5876:41765] 10.0.0 - [FirebaseAnalytics][I-ACS023220] Analytics screen reporting is enabled. Call Analytics.logEvent(AnalyticsEventScreenView, parameters: [...]) to log a screen view event. To disable automatic screen reporting, set the flag FirebaseAutomaticScreenReportingEnabled to NO (boolean) in the Info.plist
successfully saved data.'

Combine: Problem when replace addObserver with Notification publisher

i try to replace the addObserver method with Notification publisher
But i cant make it work , hope someone can help
i try to setup the publisher under viewDidLoad and receive notification from another swiftui . Since i cant make it work ,So I make it under viewWillAppear within the same swift file for debugging . In the below coding , I can only receive it from the old school method and the method from viewWillAppear not from the viewDidLoad . The setup in viewDidLoad not working and if i miss out let temp2 = under viewWillAppear , it didnt work too . Is that a bugs for combine?
Result is
BBBB
CCCC
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(forName: .dismissSwiftUI, object: nil, queue: .main) { (_) in
print("BBBB")
}
let abc = NotificationCenter.default.publisher(for: .dismissSwiftUI).sink { (_) in
print("AAAA")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// self.checkIfProfitSetup()
let temp2 = NotificationCenter.default.addObserver(forName: .dismissSwiftUI, object: nil, queue: .main) { (_) in
print("CCCC")
}
NotificationCenter.default.post(name: .dismissSwiftUI ,object: nil)
}
The .sink operator returns an AnyCancellable. So your abc property is an AnyCancellable.
The AnyCancellable documentation says
An AnyCancellable instance automatically calls cancel() when deinitialized.
Since abc is a local property, it is deinitialized when viewDidLoad returns. So your subscription is cancelled when viewDidLoad returns.
You need to store the AnyCancellable in an instance property so that it survives. Cancellable defines a store method that helps.
I usually call them “tickets” in my code, because “cancellable” is too verbose. Thus:
private var tickets: [AnyCancellable] = []
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(forName: .dismissSwiftUI, object: nil, queue: .main) { (_) in
print("BBBB")
}
NotificationCenter.default.publisher(for: .dismissSwiftUI)
.sink { _ in print("AAAA") }
.store(in: &tickets)
}

Reload/refresh a scene after receive remote notification swiftUI

I have this problem. I'm receiving a notification from CloudKit using application:didReceiveRemoteNotification in AppDelegate. I'm able to receive the recordId, fetch it, and save it successfully. The problem is, the scene doesn't refresh.
final class UserData: ObservableObject {
#Published var items: [Item] = []
func saveFetchedItem(recordId: CKRecord.ID, reason: CKQueryNotification.Reason) {
fetchAndSaveRemoteDataFromCloudKit(recordId: recordId, reason: reason, userData: self)
}
}
in AppDelegate:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let notification: CKNotification = CKNotification(fromRemoteNotificationDictionary: userInfo)!
if notification.notificationType == .query {
let queryNotification = notification as! CKQueryNotification
let recordId = queryNotification.recordID
let reason: CKQueryNotification.Reason = queryNotification.queryNotificationReason
/// reasons:
/// .recordCreated, .recordUpdated, .recordDeleted
UserData().saveFetchedItem(recordId: recordId!, reason: reason)
}
completionHandler(.newData)
}
In fetchAndSaveRemoteDataFromCloudKit, I'm passing the UserData in order to save the item received and it works. The problem is, I show the items on a List and the list doesn't refresh, even when I print the userData.items and the new item is there.
Is there a connection between AppDelegate and SceneDelegate in order to refresh the scene/window?

Firebase Storage: the uploaded image doesn't saved on the app

I upload the image via .Camera to Firebase Storage. When I closed app and run again, this image don't saved at my app. I know that I missed something. Please, tell me what I should to add. Thank's a lot!
This is my code:
import UIKit
import Firebase
import FirebaseStorage
class PicturesOfCoinsViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func saveButton(_ sender: UIButton) {
saveOneEuroCentImage()
}
#IBOutlet weak var oneEuroCentImage: UIImageView!
#IBAction func usePhotoButton(_ sender: UIButton) {
let picker = UIImagePickerController()
picker.sourceType = .camera
self.present(picker, animated: true, completion: nil)
picker.delegate = self
}
func saveOneEuroCentImage() {
let storageRef = FIRStorage.storage().reference().child("userPictures/oneEuroCent.jpg")
if let uploadData = UIImagePNGRepresentation(self.oneEuroCentImage.image!) {
storageRef.put(uploadData, metadata: nil) {(metadata, error) in
if error != nil {
print(error)
return
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
oneEuroCentImage.image = info[UIImagePickerControllerOriginalImage] as? UIImage
picker.dismiss(animated: true, completion: nil)
}
}
If you want to have a persistent copy of the image on your app then you must save the photo to your apps document directory before the upload. From your code above you are only uploading it to your cloud storage in firebase but there is no code for saving your picture locally, thats why it does not exist when the app is run again.
I suggest you create a documents directory file path or url for the image and then save it.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths.first
let imageFolderPath = path?.appending("MyFBImages")
if !FileManager.default.fileExists(atPath: imageFolderPath!){
do {
try FileManager.default.createDirectory(atPath: imageFolderPath!, withIntermediateDirectories: true, attributes: [:])
} catch let error {
print(error.localizedDescription)
}
}
let imageFilePath = imageFolderPath?.appending("myImageName.jpg")
let imageData = UIImageJPEGRepresentation(UIImage(), 1)
do {
try imageData?.write(to: URL(fileURLWithPath: imageFilePath!))
} catch let error {
print(error.localizedDescription)
}
N/B : the imageData in the code you can get that from the image you created just before the upload to firebase.
This should help you save your image locally. Next time you run your app you can access your previous images by initializing UIImage from contents of the url that holds your saved photos.
I hope this helps you out.

How to set up a minimal CKSubscription?

I want to set up a simple CKSubscription that notifies me a recordType was created, how?
After experimenting a while this is how to setup a minimal CKSubscription. You have to test it on Device, push notification does not work on simulator. You can add record in Dashboard, that will trigger push notification too.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert, categories: nil))
application.registerForRemoteNotifications()
return true
}
func someFunc() { // <- you need to call once in app life time, and again when it was removed / installed
let defaultContainer = CKContainer.defaultContainer()
let publicDatabase = defaultContainer.publicCloudDatabase
let subs = CKSubscription(recordType: "xxx", predicate: NSPredicate(value: true), subscriptionID: "yyy", options: .FiresOnRecordCreation)
subs.notificationInfo = CKNotificationInfo()
subs.notificationInfo.alertBody = "New item added"
publicDatabase.saveSubscription(subs, completionHandler: {subscription, error in})
}
func application(application: UIApplication!, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]!)
{
// <- this method will invoked
}
Did you register for notifications? You should have something like this in your application didFinishLaunchingWithOptions:
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Badge | .Sound, categories: nil))
application.registerForRemoteNotifications()
I created a working demo that is available at https://github.com/evermeer/EVCloudKitDao

Resources