fetch core data date as string to display on label - swift

I want my swift code to save 1 date in core data. on lbl1 i want the first core data date to be display. The label should only display the first date saved. Here is my code below which is not working. Nothing is being displayed on lbl1 when the function is called. I a link to my github profile below with this exact code.
https://github.com/redrock34/fetch
import UIKit
import CoreData
class ViewController: UIViewController {
var foodItems = [Food]()
var moc:NSManagedObjectContext!
var appDelegate = UIApplication.shared.delegate as? AppDelegate
var btn = UIButton()
var lbl1 = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
moc = appDelegate?.persistentContainer.viewContext
[btn,lbl1].forEach{
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
btn.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.2),
btn.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1),
btn.topAnchor.constraint(equalTo: view.topAnchor),
btn.leadingAnchor.constraint(equalTo: view.leadingAnchor),
lbl1.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.2),
lbl1.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1),
lbl1.topAnchor.constraint(equalTo: btn.bottomAnchor),
lbl1.leadingAnchor.constraint(equalTo: view.leadingAnchor),
])
btn.backgroundColor = .orange
lbl1.backgroundColor = .systemTeal
btn.addTarget(self, action: #selector(addFoodToDatabase(_:)), for: .touchUpInside)
}
#objc func addFoodToDatabase(_ sender: UIButton) {
let foodItem = Food(context: moc)
foodItem.added = NSDate() as Date
appDelegate?.saveContext()
place()
}
func place(){
let foodRequest:NSFetchRequest<Food> = Food.fetchRequest()
// 2
// 3
do {
try foodItems = moc.fetch(foodRequest)
}catch {
print("Could not load data")
}
lbl1.text = moc.name
}
}

Related

WebAVPlayerController valueForUndefinedKey,this class is not key value coding-compliant for the key playingOnMatchPointDevice

Problem Encountered with below action :
[<WebAVPlayerController 0x600001308000> valueForUndefinedKey:]: this class is not key value coding-compliant for the key playingOnMatchPointDevice." 0x00006000025e05a0
Action Tested on iOS 15+:
hit Landscape(Full Screen) icon on the Video and the video crashes when it's full screen
I had been searching and could not find any solution on this problem. I am using WKWebView in Xcode 13.
I followed this link
iOS15 Webview using `Video` causes crashes - `WebAVPlayerController valueForUndefinedKey - playingOnMatchPointDevice `
But the problem is still not solved. Your help is greatly appreciated.
here the code
import UIKit
import WebKit
class TitlePreviewViewController: UIViewController,WKUIDelegate {
private let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 22, weight: .bold)
label.text = "Harry potter"
return label
}()
private let overviewLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 18, weight: .regular)
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.text = "This is the best movie ever to watch as a kid!"
return label
}()
lazy var webView: WKWebView = {
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
let webView = WKWebView(frame:.zero,configuration: configuration)
if #available(iOS 10.0, *) {
configuration.mediaTypesRequiringUserActionForPlayback = []
} else {
configuration.requiresUserActionForMediaPlayback = false
}
webView.translatesAutoresizingMaskIntoConstraints = false
return webView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(webView)
view.addSubview(titleLabel)
view.addSubview(overviewLabel)
configureConstraints()
webView.uiDelegate = self
webView.navigationDelegate = self
}
func configureConstraints() {
let webViewConstraints = [
webView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.heightAnchor.constraint(equalToConstant: 300)
]
let titleLabelConstraints = [
titleLabel.topAnchor.constraint(equalTo: webView.bottomAnchor, constant: 20),
titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
]
let overviewLabelConstraints = [
overviewLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15),
overviewLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
overviewLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor)
]
NSLayoutConstraint.activate(webViewConstraints)
NSLayoutConstraint.activate(titleLabelConstraints)
NSLayoutConstraint.activate(overviewLabelConstraints)
}
public func configure(with model: TitlePreviewViewModel) {
titleLabel.text = model.title
overviewLabel.text = model.titleOverview
guard let url = URL(string: "https://www.youtube.com/embed/\(Video Url )") else {
return
}
webView.load(URLRequest(url: url))
}
}
extension TitlePreviewViewController: WKNavigationDelegate{
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
}
Thanks

UITapGestureRecognizer with arrangedSubviews

i add about 20+ images to the stack and by tap on image i need to change borderColor, but with this code i have error " "-[__NSArray0 tapOnView]: unrecognized selector sent to instance "
Add stack here
private lazy var mainHStack: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.distribution = .fill
stack.spacing = 8
return stack
}()
Add constraints here
scrollView.addSubview(mainHStack)
mainHStack.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
tapOnMediaView()
Configure stack here
func configureMediaViewer(withImages images: [String]) {
for image in images {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 8
imageView.clipsToBounds = true
imageView.setImage(imageUrl: image)
mainHStack.addArrangedSubview(imageView)
imageView.snp.makeConstraints { make in
make.width.height.equalTo(60)
}
}
}
Check if i tapped on image here
func tapOnMediaView() {
let arrangedImages = mainHStack.arrangedSubviews
let tap = UITapGestureRecognizer(target: arrangedImages, action: #selector(tapOnView))
if let tag = tap.view?.tag {
let currentImage = mainHStack.arrangedSubviews[tag]
currentImage.layer.borderWidth = 1
currentImage.layer.borderColor = UIColor.orange.cgColor
}
addGestureRecognizer(tap)
}
TapOnView has a delegate
#objc func tapOnView() {
delegate?.tapOnView()
}
Delegate
protocol PhotosViewProtocol: AnyObject {
func tapOnView()
}
Extension for mainVC
extension MediaViewerViewController: PhotosViewProtocol {
func tapOnView() {
print("check if works")
//not works :C
}
}
how do i change my code to get a result?

Two-way databinding using Combine

I'm building a reusable custom stepper view.
I have it all working, and am using Combine for observing value changes. However, I'd like to improve it by using two-way databinding, but not sure if that is possible?
Here is my current code:
class Stepper: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
#Published var count = 0
private let stackView = UIStackView()
private let minusButton = BorderedRoundButton()
private let plusButton = BorderedRoundButton()
private let countLabel = UILabel()
private var cancellables = Set<AnyCancellable>()
func setup() {
translatesAutoresizingMaskIntoConstraints = false
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
minusButton.setTitleColor(.primaryTint, for: .normal)
plusButton.setTitleColor(.primaryTint, for: .normal)
minusButton.setTitle("-", for: .normal)
plusButton.setTitle("+", for: .normal)
countLabel.text = "0"
countLabel.textColor = .blackText
countLabel.font = .preferredFont(forTextStyle: .body)
countLabel.textAlignment = .center
stackView.addArrangedSubview(minusButton)
stackView.addArrangedSubview(countLabel)
stackView.addArrangedSubview(plusButton)
minusButton.tapPublisher.sink { [weak self] _ in
self?.count -= 1
}.store(in: &cancellables)
plusButton.tapPublisher.sink { [weak self] _ in
self?.count += 1
}.store(in: &cancellables)
$count.map { "\($0)" }.assign(to: \.text, on: countLabel).store(in: &cancellables)
$count.map { $0 > 0 }.assign(to: \.isEnabled, on: minusButton).store(in: &cancellables)
addSubview(stackView)
NSLayoutConstraint.activate([
minusButton.widthAnchor.constraint(equalToConstant: 38),
minusButton.heightAnchor.constraint(equalToConstant: 38),
plusButton.widthAnchor.constraint(equalToConstant: 38),
plusButton.heightAnchor.constraint(equalToConstant: 38),
countLabel.widthAnchor.constraint(equalToConstant: 44),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}
}
And I am using it like this:
class PickerViewController: UIViewController {
#IBOutlet private var stepper: Stepper!
private var cancellables = Set<AnyCancellable>()
#Published var count = 0
override func viewDidLoad() {
super.viewDidLoad()
stepper.count = count
stepper.$count.sink { [weak self] value in
self?.count = value
}.store(in: &cancellables)
}
}
And that is the bit I want to improve: I now need to both set the initial value and then observe the changes. I know it's hardly a lot of code, but I am just wondering if I can do it in one line, with a sort of two-way databinding?
I thought about using SwiftUI's #Bindable propertywrapper (or a rebuilt version of it as to not have to import SwiftUI), so that PickerViewController.count is the one source, and the Stepper would automatically update it. However, then I have the problem that #Bindable is not observable itself, so these lines would no longer work:
$count.map { "\($0)" }.assign(to: \.text, on: countLabel).store(in: &cancellables)
$count.map { $0 > 0 }.assign(to: \.isEnabled, on: minusButton).store(in: &cancellables)
So my question is: can I improve the code to use two-way databinding, or should I just stick with setting the value and then observing it separately?

Why doesn't my UILabel change when I press the button?

By pressing a button in my app, the value of a variable falls by 3. While this happens without any issues, the label which uses string interpolation to show that variable as its text (label.text) does not reflect the change.
How can I make it so pressing the button changes the value of the UILabel?
import UIKit
class ViewController: UIViewController {
var token = 5
let theButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("button", for: .normal)
button.backgroundColor = .systemPink
button.addTarget(self, action: #selector(theButtonPressed), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
} else {
print("nope")
}
}
lazy var tokenLabel: UILabel = {
let label = UILabel()
label.text = "\(token)"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBlue
view.addSubview(tokenLabel)
view.addSubview(theButton)
theButton.heightAnchor.constraint(equalToConstant: 100).isActive = true
theButton.widthAnchor.constraint(equalToConstant: 200).isActive = true
theButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
theButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
tokenLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 60).isActive = true
tokenLabel.heightAnchor.constraint(equalToConstant: 300).isActive = true
tokenLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
tokenLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
}
You need to update the label's text when the button is pressed.
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
tokenLabel.text = "\(token)" // <- update
} else {
print("nope")
}
}
Or, you can observe the property token and change the label when a new value is set.
var token = 5 {
didSet {
tokenLabel.text = "\(token)"
}
}
#objc func theButtonPressed() {
if token >= 3 {
token -= 3
print("ok done")
} else {
print("nope")
}
}

Add to ContainerViews in a loop

I want to use containerviews to contain three instances of a collectionview.
My outlets are:
#IBOutlet weak var topContainer: UIView!
#IBOutlet weak var middleContainer: UIView!
#IBOutlet weak var bottomContainer: UIView!
I can do it: with a disgusting solution with repeating code in viewdidload:
topContainer.translatesAutoresizingMaskIntoConstraints = false
middleContainer.translatesAutoresizingMaskIntoConstraints = false
bottomContainer.translatesAutoresizingMaskIntoConstraints = false
// add child view controller view to container
if let controller = storyboard!.instantiateViewController(withIdentifier: "collectionscroll") as? CollectionScrollViewController {
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
topContainer.addSubview(controller.view)
NSLayoutConstraint.activate([
controller.view.leadingAnchor.constraint(equalTo: topContainer.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: topContainer.trailingAnchor),
controller.view.topAnchor.constraint(equalTo: topContainer.topAnchor),
controller.view.bottomAnchor.constraint(equalTo: topContainer.bottomAnchor)
])
controller.didMove(toParent: self)
}
if let controller = storyboard!.instantiateViewController(withIdentifier: "collectionscroll") as? CollectionScrollViewController {
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
middleContainer.addSubview(controller.view)
NSLayoutConstraint.activate([
controller.view.leadingAnchor.constraint(equalTo: middleContainer.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: middleContainer.trailingAnchor),
controller.view.topAnchor.constraint(equalTo: middleContainer.topAnchor),
controller.view.bottomAnchor.constraint(equalTo: middleContainer.bottomAnchor)
])
controller.didMove(toParent: self)
}
if let controller = storyboard!.instantiateViewController(withIdentifier: "collectionscroll") as? CollectionScrollViewController {
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
bottomContainer.addSubview(controller.view)
NSLayoutConstraint.activate([
controller.view.leadingAnchor.constraint(equalTo: bottomContainer.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: bottomContainer.trailingAnchor),
controller.view.topAnchor.constraint(equalTo: bottomContainer.topAnchor),
controller.view.bottomAnchor.constraint(equalTo: bottomContainer.bottomAnchor)
])
controller.didMove(toParent: self)
}
So to cut out repeating code I think of using a looop:
lazy var containers : [UIView] = [topContainer, middleContainer, bottomContainer]
for container in containers {
container.translatesAutoresizingMaskIntoConstraints = false
if let controller = storyboard!.instantiateViewController(withIdentifier: "collectionscroll") as? CollectionScrollViewController {
addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
topContainer.addSubview(controller.view)
NSLayoutConstraint.activate([
controller.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
controller.view.topAnchor.constraint(equalTo: container.topAnchor),
controller.view.bottomAnchor.constraint(equalTo: container.bottomAnchor)
])
controller.didMove(toParent: self)
}
}
Yet it doesn't work - the middle view does not populate and the last one does not scroll.
How can I populate my containers without copy pasta codez?
I see one error. When you transformed the code by adding the loop, you forgot to change one of the topContainers to container.
Change:
topContainer.addSubview(controller.view)
to:
container.addSubview(controller.view)