Posts

Post not yet marked as solved
1 Replies
1k Views
Hey there, I'm currently walking through Apple's official SwiftUI tutorial at https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation. In Section 8, you can show multiple devices in the canvas preview using ForEach for example. Unfortunately, my canvas always shows the first devices instead of all. In my case, "iPhone XS Max" is not showing. Does anyone know how to fix this? And where do I find the names of all other device types to add them to the device collection? Thanks in advance!
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
7 Replies
11k Views
Hello everyone, I need some help. I have absolutely no clue why my notifications are not working. My AppDelegate looks like this: import UIKit import UserNotifications @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {     /// The base UIWindow     var window: UIWindow?     func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {         let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()         print("token: \(token)")     }     func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {         print("Failed to register for remote notifications with error: \(error))")     }     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {         // Override point for customization after application launch.         UNUserNotificationCenter.current().delegate = self         UIApplication.shared.registerForRemoteNotifications()         UNUserNotificationCenter.current().requestAuthorization(             options: [.alert, .badge, .sound],             completionHandler: { (granted, error) in                 print("access granted!")                 guard granted else { return }                 DispatchQueue.main.async {                     UIApplication.shared.registerForRemoteNotifications()                     print("Registered: \(UIApplication.shared.isRegisteredForRemoteNotifications)")                 }             })         return true     }     // MARK: UISceneSession Lifecycle     func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {         // Called when a new scene session is being created.         // Use this method to select a configuration to create the new scene with.         return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)     }     func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {         // Called when the user discards a scene session.         // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.         // Use this method to release any resources that were specific to the discarded scenes, as they will not return.     } } The problem is, function "didRegisterForRemoteNotificationsWithDeviceToken" is never getting called. I also created "Apple Push Notification service SSL Certificates" in my developer account, added "Push Notifications" to my capabilities in Xcode but it's still not working. Every time I tab on "Allow" to allow notifications, it says "access granted", but it does not print out any device token. "isRegisterForRemoteNotifications" also returns true. I also searched on the internet for around 2-3 hours, but I couldn't find any solution yet. I'm using Xcode 12 Beta 2 and iOS 14 Dev Beta 2. Thank you.
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
0 Replies
452 Views
I'm trying to fetch update news from rss feed every hour. Unfortunately, I sometimes get the following error: simplexml_load_file(https://developer.apple.com/news/releases/rss/releases.rss): failed to open stream: HTTP request failed! HTTP/1.0 401 Unauthorized I do not need to login to access that feed directly in my browser. But for some reason, my server runs into some problems with this. Anyone has an idea how to fix this? Thank you
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
2 Replies
306 Views
Hello everyone, I‘m trying to fetch JSON data from an url, building objects and saving them into core data. For example: { code: 200, data: [ 	{ 	 „id“: 1, 	 „name“: „Peter“, 	 „age“: 35, 	 „email“: „peter@example.com“ 	}, 	{ 	 „id“: 2, 	 „name“: „Tim“, 	 „age“: 62, 	 „email“: „tim@example.com“ 	}, 	... ] } „data“ contains „Person“ objects (or customers in my case containing name, address, etc. ... for example). Unfortunately, there‘s only one of these values stored in CoreData (in my example the firstname of a Person or „name“ in this case). CoreData creates new „Person“ objects for each but only stores one of it‘s values only. Do you have an idea why CoreData doesn‘t store everything and just a single value only? Everything else is always nil, I checked the debug. Thank you in advance.
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
0 Replies
362 Views
Hello everyone. Let me say, I have the following template (I created something similar using PHP and HTML, but I want to create an app as well): img.mickedplay.de/apple-forum-screenshot-1.png Dark gray = Header Light blue = Image Green = Checkbox Yellow = Textlabel Orange = Textfield (some of them have different functions) Purple = Textarea Red = signature field Dark blue = some other similar content This could be something like a contract paper I want to create using Swift. Almost every element is surrounded by a small border and text fields for example are invisible (the user just need to tap into the empty field inside of the border lines to take action. He could always use two fingers to zoom in (but the paper should keep it's static size). Finally after the user filled out everything, it should create a pdf file of it for example. Unfortunately I don't know how to start and how to keep the original size (it's measured in cm). It should have the size of A4 and should look the same on iPhone, iPad and macOS without distortion. So, I think I have to create a new view and draw lines next to each others, adding text fields, checkboxes, labels and so on. I hope you understand what I'm trying to do, my english is horrible. 🙄 Thanks for helping.
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
10 Replies
1.3k Views
Hey everybody.I'm in trouble with UISplitViewController which does not seem to work right as I want. On iPhone, everthing looks working fine, but not on the iPad.After the app has started, it looks like this: https://img.mickedplay.de/apple-1.pngAfter selecting a cell from the left table view, it looks like this: https://img.mickedplay.de/apple-2.pngThe title bar disappeared for an unknown reason. Do you know how to fix this? I also took a look into the Storyboard of Apple's MasterDetailApp demo but I could not see any difference between those and mine.And do you know how to move the plus-icon from the title bar next to the search bar? (https://img.mickedplay.de/apple-3.png).Thank you in advance and have a nice day!
Posted
by Pinnokkio.
Last updated
.
Post not yet marked as solved
4 Replies
2.7k Views
Hey everybody,first of all, I'm new in Swift (but not new in software development).I'm currently trying to create a private app which is used at work for another person.It should be possible to create/add/edit or delete customers which are displayed in UITableView and Managed in UITableViewController.I created a small caching system:1. Fetch data from API (an URL which returns JSON)2. Store data (in my case, an array of customers: [Customer]) on device (as JSON or is there any better way to store an array with custom objects?)3. If user restarts app or refreshes table within X minutes, load data from cache, otherwise fetch again from API.Fetching first time from the API works fine and the data is getting inserted into the table. But getting the data from cache, does not work even if it's exactly the same array [Customer].I found out, thatoverride func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {is not even get called, and I have absolutely no idea why it works fetching from API but not from cache.CustomerListController:// // CustomerController.swift // // Copyright © 2020 XXXXX. All rights reserved. // import UIKit class CustomerListController: BaseTableController { /// The table view instance @IBOutlet var customerTableView: UITableView! /// List of all customers, fetched from the API var customersList: [Customer] = [] /// List of all customers, filtered by search controller var filteredCustomersList: [Customer] = [] /// Array of customers, sorted in sections var sectionCustomers: [Dictionary<String, [Customer]>.Element] = [] /// Array of filtered customers, sorted in sections var filteredSectionCustomers: [Dictionary<String, [Customer]>.Element] = [] /// The search controller var searchController: UISearchController! /** * viewDidLoad() */ override func viewDidLoad() { super.viewDidLoad() // self.customerTableView.tintColor = Constants.COLOR_ON_PRIMARY_BLUE // self.navigationController?.navigationBar.barTintColor = .red UITabBar.appearance().tintColor = Constants.COLOR_ON_PRIMARY_BLUE UITabBar.appearance().barTintColor = Constants.COLOR_PRIMARY_BLUE // Do any additional setup after loading the view. self.customerTableView.delegate = self self.customerTableView.dataSource = self self.title = "Customers" self.configureRefreshControl() self.configureSearchController() // @NOTE: SectionBar foreground color self.customerTableView.tintColor = Constants.COLOR_PRIMARY_BLUE // @NOTE: Loads the data into the table self.loadData() } /** * Loads the data from cache or refreshes it from the JSON API. */ func loadData() { let current = Date() let lastCustomerFetch = UserDefaults.standard.object(forKey: Constants.UD_CUSTOMER_LAST_FETCH) as? Date print("Last fetch: \(lastCustomerFetch!)") print("--------------------------------------------------------------------") if lastCustomerFetch != nil { if lastCustomerFetch!.distance(to: current) >= 900 { self.fetchJSONDataAndUpdateTable(cachedAt: current, onFetchComplete: { () -> Void in self.reloadTableData() }) } else { do { let storedObjItem = UserDefaults.standard.object(forKey: Constants.UD_CUSTOMER_CACHE) self.customersList = try JSONDecoder().decode([Customer].self, from: storedObjItem as! Data) } catch { Alert(title: "Error", message: error.localizedDescription).show() } print("Updated customers from cache (\(self.customersList.count) entries)") print(self.customersList) // @NOTE: Reload table view self.reloadTableData() } } else { self.fetchJSONDataAndUpdateTable(cachedAt: current, onFetchComplete: { () -> Void in self.reloadTableData() }) } } /** * Fetches the json data from an url. * - Parameter cachedAt: The caching time. * - Parameter onFetchComplete: What happens, if the fetch has been completed. */ func fetchJSONDataAndUpdateTable(cachedAt: Date, onFetchComplete: @escaping () -> Void) { // @NOTE: Direct JSON URL var apiParameters = [ "method": "customers", "limit": 25 ] guard let url = APIUtilities.buildAPIURL(parameters: &apiParameters) else { Alert(title: "Error", message: "Failed to build api url.").show() return } // @NOTE: Fetches the JSON from tha API-URL and handles it's result. JSONUtilities.getJSONFromURL(url: url, handleURLData: { (data) in do { let decodedResponseJSON = try JSONDecoder().decode(GetCustomerJSONStruct.self, from: data) // @NOTE: Store basic data in memory self.customersList = decodedResponseJSON.data ?? [] // @NOTE: Sort into alphabetical sections self.sectionCustomers = self.orderCustomersIntoSections() // @NOTE: Store basic data in cache if let encodedCustomers = try? JSONEncoder().encode(self.customersList) { UserDefaults.standard.set(encodedCustomers, forKey: Constants.UD_CUSTOMER_CACHE) } UserDefaults.standard.set(cachedAt, forKey: Constants.UD_CUSTOMER_LAST_FETCH) print("Updated customers from API (\(self.customersList.count) entries)") print(self.customersList) onFetchComplete() } catch { DispatchQueue.main.async { Alert(title: "Error", message: "Failed to decode JSON.").show() } } }) } /* * Reloads the table view containing the customer data. */ func reloadTableData() { print("Refreshing data...") DispatchQueue.main.async { self.customerTableView.reloadData() print("Refresh complete!") } } /** * Order the customers into alphabet-based bsections. */ func orderCustomersIntoSections() -> [Dictionary<String, [Customer]>.Element] { var orderedSections: [String:[Customer]] = [:] // @NOTE: Order customers into sections relative to the first character of their display name for customer in self.customersList { var firstDisplayCharacter = String(customer.getDisplayName().string.prefix(1)).uppercased() let range = firstDisplayCharacter.rangeOfCharacter(from: CharacterSet.letters) if range == nil { firstDisplayCharacter = "#" } // @NOTE: Create new section if it doesn't exist yet if orderedSections[firstDisplayCharacter] == nil { orderedSections[firstDisplayCharacter] = [] } orderedSections[firstDisplayCharacter]?.append(customer) } return orderedSections.sorted { (first, second) -> Bool in return first.key < second.key } } /** * Adds the refresh control to the table view. */ func configureRefreshControl () { self.customerTableView.refreshControl = UIRefreshControl() self.customerTableView.refreshControl?.tintColor = Constants.COLOR_ON_PRIMARY_BLUE self.customerTableView.refreshControl?.addTarget(self, action: #selector(handleRefreshControl), for: .valueChanged) self.customerTableView.refreshControl?.attributedTitle = NSAttributedString( string: "Pull down to refresh", attributes: [.foregroundColor: Constants.COLOR_ON_PRIMARY_BLUE] ) } /** * Adds the search field on top of the table. */ func configureSearchController() { self.searchController = super.configureSearchController( placeholder: "Search...", scopeButtonTitles: [Constants.CUSTOMER_SEARCH_SCOPE_NAME, Constants.CUSTOMER_SEARCH_SCOPE_ADDRESS], tintColor: Constants.COLOR_ON_PRIMARY_BLUE, backgroundColor: Constants.COLOR_PRIMARY_BLUE ) self.searchController.searchResultsUpdater = self self.searchController.searchBar.delegate = self self.navigationItem.searchController = self.searchController self.navigationItem.hidesSearchBarWhenScrolling = false } /** * Handles the table view refresh control. */ @objc func handleRefreshControl() { // @TODO: Refresh // Dismiss the refresh control. DispatchQueue.main.async { self.customerTableView.refreshControl?.endRefreshing() } } /** * Filters the customers by the given scope. */ func filterCustomersForSearch(searchText: String, scope: String) { let lowercasedSearchText = searchText.lowercased() self.filteredSectionCustomers = [] if self.isSearchBarEmpty() { self.filteredSectionCustomers = self.sectionCustomers } else { switch(scope) { case Constants.CUSTOMER_SEARCH_SCOPE_NAME: for (sectionTitle, entry) in self.sectionCustomers { var tempCustomers: [Customer] = [] for customer in entry { if customer.getDisplayName().string.lowercased().contains(lowercasedSearchText) { tempCustomers.append(customer) } } if tempCustomers.count > 0 { self.filteredSectionCustomers.append((sectionTitle, tempCustomers)) } } break; case Constants.CUSTOMER_SEARCH_SCOPE_ADDRESS: for (sectionTitle, entry) in self.sectionCustomers { var tempCustomers: [Customer] = [] for customer in entry { if customer.getDisplayAddress().lowercased().contains(lowercasedSearchText) { tempCustomers.append(customer) } } if tempCustomers.count > 0 { self.filteredSectionCustomers.append((sectionTitle, tempCustomers)) } } break; default: break; } } self.reloadTableData() } /** * - Returns: TRUE, if the search bar is empty, otherwise FALSE. */ func isSearchBarEmpty() -> Bool { return self.searchController.searchBar.text?.isEmpty ?? true } /** * - Returns: TRUE, if the user is searching, otherwise FALSE. */ func isUserSearching() -> Bool { let searchBarScopeIsFiltering = self.searchController.searchBar.selectedScopeButtonIndex != 0 return self.searchController.isActive && (!self.isSearchBarEmpty() || searchBarScopeIsFiltering) } } extension CustomerListController { /** * This is called for every table cell. */ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "CustomerCell") as? CustomerCell else { return UITableViewCell() } let currentCustomer = self.isUserSearching() ? self.filteredSectionCustomers[indexPath.section].value[indexPath.row] : self.sectionCustomers[indexPath.section].value[indexPath.row] cell.customerDisplayName.attributedText = currentCustomer.getDisplayName() cell.customerDisplayAddress.text = currentCustomer.getDisplayAddress() return cell } /** * Returns the amount of sections. */ override func numberOfSections(in tableView: UITableView) -> Int { return self.isUserSearching() ? self.filteredSectionCustomers.count : self.sectionCustomers.count } /** * Returns the amount of rows in a section. */ override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.isUserSearching() ? self.filteredSectionCustomers[section].value.count : self.sectionCustomers[section].value.count } /** * Set's the title for sections. */ override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return (ListUtilities.getKeysFromTuples( tuple: (self.isUserSearching() ? self.filteredSectionCustomers : self.sectionCustomers) ) as? [String])?[section] } /** * The section index title on the right side of the table view. */ override func sectionIndexTitles(for tableView: UITableView) -> [String]? { return ListUtilities.getKeysFromTuples( tuple: self.isUserSearching() ? self.filteredSectionCustomers : self.sectionCustomers ) as? [String] } /** * Called, whenever a user deselectes a table cell. */ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { performSegue(withIdentifier: "showCustomerDetail", sender: self) } /** * Prepares the segue to open. */ override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let destination = segue.destination as? CustomerDetailController { let indexPath = self.customerTableView.indexPathForSelectedRow guard let selectedSection = indexPath?.section else { return } guard let selectedRow = indexPath?.row else { return } let customerList = self.isUserSearching() ? self.filteredSectionCustomers : self.sectionCustomers destination.customer = customerList[selectedSection].value[selectedRow] } } } extension CustomerListController: UISearchBarDelegate, UISearchResultsUpdating { /** * Called when the suer changes the search scope. */ func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { self.filterCustomersForSearch(searchText: searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope]) } /** * Called when the search results need tp be updated (e.g. when the user types a character in the search bar) */ func updateSearchResults(for searchController: UISearchController) { let searchBar = self.searchController!.searchBar let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex] self.filterCustomersForSearch(searchText: self.searchController!.searchBar.text!, scope: scope) } }Class "BaseTableController" extends from UITableViewController and does not contain important things.I hope, you can help me and I reall appreciate your support.Thank you!
Posted
by Pinnokkio.
Last updated
.