8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

首次加载时来自 URL 的 UITableViewCell 图像错误

alexmherrmann 2月前

218 0

情况将 url 图像设置为 UITableViewCell 时出现问题。我创建了 CancelableImageView,它是自定义 UIImageView,用于在有新图像时取消图像下载和设置任务……

情况

将 url 图像设置为 UITableViewCell 时出现了问题。我创建了自定义 CancelableImageView UIImageView 当设置新图像时取消图像下载和设置任务。使用此方法,“错误图像”问题似乎已解决,但这仍然发生在 UITableView 上

加载 UITableView 第一个单元格 完成加载图像并更改图像后, 第四个单元格 的图像也更改为 第一个单元格的图像 。 滚动后,第四个单元格的图像更改为正确的图像。

代码

这是我的 UIImage 图像加载扩展(包含图像缓存)

/// Singleton for Image Caching
class ImageCacheManager {
    
    /// Storage to save cached UIImage
    private let cache = Cache<String, UIImage>()
    
    /// singleton instance
    static let shared = ImageCacheManager()
    
    /**
    Get image from cache data for url String
    - Parameter key:  String url of UIImage
    - Returns: Retrun cached image for url. Retrun nil when cached image is not exist
    */
    func loadCachedData(for key: String) -> UIImage? {
        let itemURL = NSString(string: key)
        return cache.value(forKey: key)
    }
    
    /**
    Save UIImage to cache data
     - Parameters:
        - image: UIImage to save in cache data
        - key:  String url of UIImage
     */
    func saveCacheData(of image: UIImage, for key: String) {
        let itemURL = NSString(string: key)
        cache.insertValue(image, forKey: key)
    }
}

extension UIImageView {

    /**
     Set image to UIImageView with Cached Image data or data from URL
     - Parameters:
        - urlString: String url of image
        - forceOption: Skip getting image from cache data and force to get image from url when true. default false
     */
    func loadImage(_ urlString: String?, forceOption: Bool = false) -> UIImage? {
        guard let imagePath = urlString else { return nil }
        
        // Cached Image is available
        if let cachedImage = ImageCacheManager.shared.loadCachedData(for: imagePath), forceOption == false {
            return cachedImage
            
            // No Image Cached
        } else {
            guard let imageURL = URL(string: imagePath) else { return nil }
            guard let imageData = try? Data(contentsOf: imageURL) else { return nil }
            guard let newImage = UIImage(data: imageData) else { return nil }
            
            ImageCacheManager.shared.saveCacheData(of: newImage, for: imagePath)
            return newImage
        }
    }
    
    func setImage(_ urlString: String?, forceOption: Bool = false) {
        DispatchQueue.global().async {
            guard let image = self.loadImage(urlString, forceOption: forceOption) else { return }
            
            DispatchQueue.main.async {
                self.image = image
            }
        }
    }
}

这是自定义 UIImage,当设置新图像时取消图像加载任务:

/// UIImageView with async image loading functions
class CancelableImageView: UIImageView {
    
    /// Cocurrent image loading work item
    private var imageLoadingWorkItem: DispatchWorkItem?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    init() {
        super.init(frame: CGRect.zero)
    }
    
}

// MARK: Concurrent image loading method
extension CancelableImageView {
    
    /**
     Cancel current image loading task and Set image to UIImageView with Cached Image data or data from URL
     - Parameters:
        - urlString: String url of image
        - forceOption: Skip getting image from cache data and force to get image from url when true. default false
     */
    func setNewImage(_ urlString: String?, forceOption: Bool = false) {
        
        self.cancelLoadingImage()
        self.imageLoadingWorkItem = DispatchWorkItem { super.setImage(urlString, forceOption: forceOption) }
        self.imageLoadingWorkItem?.perform()
    }
    
    /// Cancel current image loading work
    func cancelLoadingImage() {
        DispatchQueue.global().async {
            self.imageLoadingWorkItem?.cancel()
        }
    }
}

这是该视图的 UITableViewCell:

class ChartTableViewCell: UITableViewCell {

    lazy var posterImageView = CancelableImageView().then {
        $0.contentMode = .scaleAspectFit
        $0.image = UIImage(named: "img_placeholder")
    }
    
    ... 

    override func prepareForReuse() {
        setPosterPlaceholderImage()
        super.prepareForReuse()
    }
}

extension ChartTableViewCell {
    
    /// Set poster imageView placeholder Image
    private func setPosterPlaceholderImage() {
        self.posterImageView.image = UIImage(named: "img_placeholder")
    }
    
    // MARK: Set Data
    func setData(rank: Int, movie: MovieFront) {
        
        rankLabel.text = "\(rank+1)"
        titleLabel.text = movie.title
        genreLabel.text = movie.genre
        releaseDateLabel.text = movie.releaseDate
        starRating.rating = movie.ratingScore/2
        ratingCountLabel.text = "(\(movie.ratingCount))"
        if let imagePath = movie.posterPath {
            posterImageView.setNewImage(APIService.configureUrlString(imagePath: imagePath))
        }
    }
}

这是 UITableViewDataSource (cellForRowAt):

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: identifiers.chart_table_cell) as? ChartTableViewCell else {
            return UITableViewCell()
        }
        
        cell.setData(rank: indexPath.row, movie: viewModel.movieListData.value[indexPath.row])
        return cell
    }
帖子版权声明 1、本帖标题:首次加载时来自 URL 的 UITableViewCell 图像错误
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由alexmherrmann在本站《uitableview》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 一些观察结果:

    1. 点1

      点2

    2. p3

      p4

    3. p5

    坦白说,以上是关于修复图像视图的异步图像检索/缓存功能中的问题的一般性观察,但您可能还遇到了另一个问题。具体来说,以上修复了由于滚动单元格而引起的问题,但您的动画 gif 显示了另一个问题,即更新第一个单元格的图像似乎正在更新第四个单元格的图像。这可能是上述第三点的表现,也可能是其他原因。这里没有足够的信息来诊断它。我建议修复上述问题,如果您仍然遇到问题,请使用 MRE 发布新问题以帮助进一步诊断。

    但是,坦率地说,我可能会鼓励您考虑建立异步图像检索和缓存库,例如 KingFisher、SDWebImage、AlamofireImage 等。所有这些都足够复杂,因此明智的做法是不要“重新发明轮子”。

  • 我似乎无法格式化保存到 localStorage 的数组。您可以更改数组的索引值吗?我有一个这样的数组对象:const myArray = [{id: 41, name: \'x\'}, {i...

    我似乎无法格式化保存到 localStorage 的数组。您可以更改数组的索引值吗?我有一个这样的数组对象:

    const myArray = [{id: 41, name: "x"}, {id: 42, name: "y"}]
    

    但我想把它做成这样:

    const myArray = [ 41: {id:41, name:"x" }, 42: {id:41, name:"y" }}
    

    因此对象的 id 成为数组的索引

    如果这不可能那么这样就可以了:

    const myArray = [ {41: {id:41, name:"x"} }, {42: {id:41, name:"y"}}]
    

    因此基本上对象的 id 成为该对象的索引或容器对象。

  • sci9 2月前 0 只看Ta
    引用 4

    我有一个对象数组,需要访问每个日期的值。我需要遍历每个日期值并将它们与当前日期进行核对。重要的是,返回的日期值位于

    我有一个对象数组,需要访问每个日期的值。我需要遍历每个日期值并将它们与当前日期进行核对。
    重要的是,返回的日期值的格式是 DD/MM/YYYY 不显示时间的。

    PS 抱歉,我是 Javascript 新手,不太清楚我是否以正确的方式执行此操作

    我非常感谢任何建议!

    const menu = [
     {
     id: 1,
     title: "title of item one",
     date: "22/12/2023",
     },
     {
     id: 2,
     title: "title of item two",
     date: "01/02/2024",
     },
     {
     id: 3,
     title: "title of item three",
     date: "18/04/2024",
     },
    ]
    
    let objectDate = menu.date;
    
    let date = new Date();
    let day = date.getDate();
    let month = date.getMonth() + 1;
    let year = date.getFullYear();
    
    const currentDate = day + "-" + month + "-" + year;
    
    for (let i=0; i < menu.length; i++) {
    
     if (currentDate > objectDate) {
      // objectDate = "Sorry, this offer is expired";
      console.log("Sorry this deal is expired");
     }
     else if (currentDate === objectDate) {
      //objectDate = "This offer expires TODAY!";
      console.log("Hurry! Expires TODAY");
     }
     else {
      //objectDate = "Offer expires on " + objectDate;
      console.log("Expires on " + objectDate);
     }
    };  
    
  • JavaScript 中的实际数组只能具有从零开始的连续数字索引。你想要的只能通过使用对象而不是数组来实现,并赋予它

  • \'使用值而不是数组对象中的索引\' 在数组中,不行。在对象中,可以。您的第三个示例(创建对象数组)将是一个很好的解决方案。您还可以将整个对象变成一个对象,然后使用循环遍历它

  • 尝试在 for 循环中创建对象日期。以便您可以访问当前迭代日期 menu[i].date 。还要使用 DD/MM/YYYY 格式(而不是 DD-MM-YYYY)创建当前日期变量。

    尝试一下这两个改变。

  • 也许应该写一下如何做,而不是仅仅建议并说“自己尝试一下”。那将是一个答案。这最多是一个评论(我知道你还做不到,但然后尝试给出一个好的答案,以更好地帮助你完成这里描述的事情,因为 OP 显然还没有达到程序员的水平)

  • 您无法直接将数组中元素的键更改为特定值(如对象的属性)。但您可以创建一个对象,其中键是 ID,值是相应的对象。

    const myArray = [{id: 41, name: "x"}, {id: 42, name: "y"}];
    const myObject = {};
    
    // Convert array to object
    myArray.forEach(item => {
        myObject[item.id] = item;
    });
    
    // Now myObject will look like:
    // { 41: {id:41, name:"x"}, 42: {id:42, name:"y"} }
    
    // If you still need it as an array of objects with IDs as keys:
    const newArray = Object.keys(myObject).map(key => ({ [key]: myObject[key] }));
    
    // Now newArray will look like:
    // [ {41: {id:41, name:"x"} }, {42: {id:42, name:"y"}} ]
    
  • 你见过这行问题吗?他想检查对象中的每个日期。你的代码只会检查对象中的第一个日期……不是吗?

    1. 您在 JSON 中有一个由 \'/\' 分隔的日期,但通过 \'-\' 将其设置为变量
    2. 您应该比较数字,但您却在比较字符串。如果您不知道,请学习类型转换,然后进行比较:首先将年份与年份进行比较,然后将月份与月份进行比较,如果其余的都相等,则将日期与日期进行比较。

    正确的代码:

    const menu = [
     {
     id: 1,
     title: "title of item one",
     date: "22-12-2023",
     },
     {
     id: 2,
     title: "title of item two",
     date: "01-02-2024",
     },
     {
     id: 3,
     title: "title of item three",
     date: "18-04-2024",
     },
    ]
    
    let objectDate = menu[0].date;
    
    let currentDate = new Date();
    let currentDay = date.getDate();
    let currentMonth = date.getMonth() + 1;
    let currentYear =  date.getFullYear();
    
    
    for (let i=0; i < menu.length; i++) {
    
     if (currentYear >  parseInt(objectDate.slice(0,2)) or currentMonth > parseInt(objectDate.slice(4,6)) or currentDay > parseInt(objectDate.slice(8,10))) {
      // objectDate = "Sorry, this offer is expired";
      console.log("Sorry this deal is expired");
     }
     else if (currentDate === objectDate) {
      //objectDate = "This offer expires TODAY!";
      console.log("Hurry! Expires TODAY");
     }
     else {
      //objectDate = "Offer expires on " + objectDate;
      console.log("Expires on " + objectDate);
     }
    };  
    
  • 我为 tableview 创建了一个删除按钮,通过平移手势滑动即可显示。我可以使用 UIContextualAction 来完成此操作,但我无法自定义按钮的外观。所以我决定...

    我为 tableview 创建了一个删除按钮,通过平移手势滑动即可显示。我可以使用 UIContextualAction 来完成此操作,但我无法自定义按钮的外观。所以我决定自己制作按钮。我创建的平移手势功能也有效,但存在一个问题。当我按住单元格(长按)并将单元格向左滑动时,单元格会立即返回到之前的状态。我该如何防止这种情况发生?有两个与此主题相关的类,分别称为 TableViewCell 和 ViewController

    这是我的 TableViewCell 类

    
    
    import UIKit
    import CoreData
    
    protocol TableViewCellDelegate : AnyObject {
        func didRequestDelete(_ cell: TableViewCell)
    }
    
    class TableViewCell: UITableViewCell {
    
        let titleLabel = UILabel()
        let noteLabel = UILabel()
        let dateLabel = UILabel()
        let timeLabel = UILabel()
        let dateFormatter = DateFormatter()
        let timeFormatter = DateFormatter()
        let deleteButton = UIButton()
        weak var delegate : TableViewCellDelegate?
    
        
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
    
            dateFormatter.dateFormat = "dd/MM/yyyy"
            timeFormatter.dateFormat = "HH:mm"
    
            selectionStyle = .none
            setupDeleteButton()
            
            contentView.layer.cornerRadius = 15
            contentView.layer.borderWidth = 2
            contentView.clipsToBounds = false
            backgroundColor = UIColor.clear
            backgroundView?.backgroundColor = UIColor.clear
            selectedBackgroundView?.backgroundColor = UIColor.clear
            
            setLabel(label: titleLabel, textColor: .systemGray5, fontSize: 22, numberOfLine: 0).isEnabled = false
            setLabel(label: noteLabel, textColor: .systemGray5, fontSize: 18, numberOfLine: 3).isHidden = false
            setLabel(label: dateLabel, textColor: .systemGray, fontSize: 14, numberOfLine: 1).isHidden = false
            setLabel(label: timeLabel, textColor: .systemGray, fontSize: 14, numberOfLine: 1).isHidden = false
            
            addContentView(views: [titleLabel,noteLabel,dateLabel,timeLabel])
           
            let colorIndex = UserDefaults.standard.integer(forKey: "index")
            setupBasedOnColors(index: colorIndex)
            setupConstraints()
            
            let leftSwipeGesture = UIPanGestureRecognizer(target: self, action: #selector(handleLeftSwipe(_:)))
            contentView.addGestureRecognizer(leftSwipeGesture)
            
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleCellTap(_:)))
            tapGesture.delegate = self
            contentView.addGestureRecognizer(tapGesture)
    
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            let pointForTargetView = deleteButton.convert(point, from: self)
            if deleteButton.bounds.contains(pointForTargetView) {
                return deleteButton
            }
            return super.hitTest(point, with: event)
        }
    
        
        func setupBasedOnColors(index: Int){
            switch index {
            case 0:
                contentView.layer.borderColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1).cgColor
            case 1:
                contentView.layer.borderColor = UIColor.systemPink.cgColor
            case 2:
                contentView.layer.borderColor = UIColor.systemGray3.cgColor
            case 3:
                contentView.layer.borderColor = UIColor.systemBlue.cgColor
            case 4:
                contentView.layer.borderColor = UIColor.systemYellow.cgColor
            case 5:
                contentView.layer.borderColor = UIColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 1).cgColor
            default:
                print("Renk Bulunamadı")
            }
            contentView.setNeedsDisplay()
        }
        
        func setupDeleteButton(){
            contentView.addSubview(deleteButton)
            deleteButton.setImage(UIImage(systemName: "trash"), for: .normal)
            deleteButton.layer.cornerRadius = 15
            deleteButton.tintColor = .white
            deleteButton.addTarget(self, action: #selector(deleteButtonTapped), for: .touchUpInside)
            deleteButton.isUserInteractionEnabled = true
        }
        
        func setLabel(label: UILabel, textColor : UIColor, fontSize: CGFloat, numberOfLine: Int) -> UILabel {
            label.textColor = textColor
            label.font = UIFont.systemFont(ofSize: fontSize)
            label.numberOfLines = numberOfLine
            return label
        }
        
        func addContentView(views: [UILabel]){
            views.forEach { view in
                contentView.addSubview(view)
            }
        }
    
        private func setupConstraints() {
            titleLabel.translatesAutoresizingMaskIntoConstraints = false
            noteLabel.translatesAutoresizingMaskIntoConstraints = false
            dateLabel.translatesAutoresizingMaskIntoConstraints = false
            timeLabel.translatesAutoresizingMaskIntoConstraints = false
            deleteButton.translatesAutoresizingMaskIntoConstraints = false
    
            NSLayoutConstraint.activate([
                titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
                titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
                titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
                
                deleteButton.leadingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 6),
                deleteButton.topAnchor.constraint(equalTo: contentView.topAnchor),
                deleteButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
                deleteButton.widthAnchor.constraint(equalToConstant: 100),
                
                noteLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5),
                noteLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
                noteLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
                noteLabel.bottomAnchor.constraint(equalTo: dateLabel.topAnchor, constant: -10),
                
                dateLabel.topAnchor.constraint(equalTo: noteLabel.bottomAnchor, constant: 10),
                dateLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
                dateLabel.trailingAnchor.constraint(equalTo: timeLabel.leadingAnchor, constant: -15),
                dateLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10),
                
                timeLabel.topAnchor.constraint(equalTo: dateLabel.topAnchor),
                timeLabel.leadingAnchor.constraint(equalTo: dateLabel.trailingAnchor, constant: 20),
                timeLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -9)
            ])
        }
    
        func configure(with note: NoteText) {
            titleLabel.text = note.title
            noteLabel.text = note.text
            if let date = note.date {
                timeLabel.text = timeFormatter.string(from: date)
            } else {
                timeLabel.text = "No time"
            }
            
            if let date = note.date {
                   configureCellDateLabel(with: date)
               } else {
                   dateLabel.text = "No date"
               }
        }
        
        func configureCellDateLabel(with date: Date) {
            let calendar = Calendar.current
            if calendar.isDateInToday(date) {
                dateLabel.text = "Today"
            } else {
                dateFormatter.dateFormat = "dd/MM/yyyy"
                dateLabel.text = dateFormatter.string(from: date)
            }
        }
        
        @objc func handleLeftSwipe(_ gesture: UIPanGestureRecognizer) {
            let translation = gesture.translation(in: contentView)
            if gesture.state == .changed {
                let newPosition = max(translation.x, -(deleteButton.frame.width + 7))
                if newPosition <= 0 {
                    contentView.frame.origin.x = newPosition
                }
            } else if gesture.state == .ended {
                let shouldRevealButton = contentView.frame.origin.x < -deleteButton.frame.width / 2
                UIView.animate(withDuration: 0.3) {
                    self.contentView.frame.origin.x = shouldRevealButton ? -(self.deleteButton.frame.width + 7) : 0
                }
            }
        }
        
        @objc func handleCellTap(_ gesture: UITapGestureRecognizer) {
            if contentView.frame.origin.x != 0 {
                UIView.animate(withDuration: 0.3) {
                    self.contentView.frame.origin.x = 0
                }
            }
        }
        override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            return contentView.frame.origin.x != 0
        }
    
        @objc func deleteButtonTapped(){
            delegate?.didRequestDelete(self)
        }
    }
    

    我尝试在 ViewController 类的 didSelectRowAt 函数中添加一些条件,但没有效果。

    import UIKit
    import CoreData
    
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, TableViewCellDelegate {
        
    
    
        var context: NSManagedObjectContext!
        let tableView = UITableView()
        let createNoteButton = UIButton()
        let cellSpacing : CGFloat = 6
        var fetchedNotes: [NoteText] = []
        var titleLabel = UILabel()
        var selectedIndexPath: IndexPath?
        var randomLabel = UILabel()
        var randomColor = UIColor()
        var randomBool = Bool()
        let dateFormatter = DateFormatter()
        let timeFormatter = DateFormatter()
        
        lazy var optionsMarkItem : UIBarButtonItem = {
            let item = UIBarButtonItem(image: UIImage(systemName: "gearshape.fill"), style: .plain, target: self, action: #selector(optionsButtonTapped))
            item.tintColor = .systemYellow
            return item
        }()
        
    
    
        //MARK: viewDidLoad
        
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .black
            setupTableView()
            
            for family in UIFont.familyNames.sorted() {
                print("\(family)")
                for name in UIFont.fontNames(forFamilyName: family).sorted() {
                    print("== \(name)")
                }
            }
    
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
                fatalError("Cannot retrieve app delegate")
            }
            context = appDelegate.persistentContainer.viewContext
    
            setupCreateNoteButton()
            randomLabel.isHidden = true
            setupTitleLabel()
            tableView.backgroundColor = .black
            tableView.delegate = self
            tableView.dataSource = self
            fetchNotes()
            navigationItem.rightBarButtonItem = optionsMarkItem
            
            let longPressGestureButton = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressCell))
            let longPressGestureCell = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressButton))
            longPressGestureCell.minimumPressDuration = 0.2
            longPressGestureButton.minimumPressDuration = 0.2
            
            tableView.addGestureRecognizer(longPressGestureButton)
            createNoteButton.addGestureRecognizer(longPressGestureCell)
            
            let switchValue = UserDefaults.standard.bool(forKey: "mySwitchValue")
            setupUIBasedOnSwitch(switchValue: switchValue)
            
        }
        
        // MARK: viewWillAppear
        
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            fetchNotes()
            tableView.delegate = self
            tableView.dataSource = self
            
            let switchValue = UserDefaults.standard.bool(forKey: "mySwitchValue")
            setupUIBasedOnSwitch(switchValue: switchValue)
            dateFormatter.dateFormat = "dd/MM/yyyy"
            timeFormatter.dateFormat = "HH:mm"
            
            let colorIndex = UserDefaults.standard.integer(forKey: "index")
            setupBasedOnColors(index: colorIndex)
        }
        
        // MARK: UserDefaults get functions
        
        func getIndexValue() -> Int{
            let index = UserDefaults.standard.integer(forKey: "index")
            return index
        }
    
        //MARK: Core Data Fonksiyonları
        
        func fetchNotes() {
            let request: NSFetchRequest<NoteText> = NoteText.fetchRequest()
            do {
                fetchedNotes = try context.fetch(request)
            } catch {
                print("Not çekme hatası: \(error)")
            }
            tableView.reloadData()
        }
        
        func addNoteWithTitle(_ title: String, text: String, date: Date, time: Date) {
            let newNote = NoteText(context: context)
            newNote.title = title
            newNote.text = text
            newNote.date = date
            newNote.time = date
            do {
                try context.save()
                fetchNotes() // Listeyi güncelle
            } catch {
                print("Not kaydetme hatası: \(error)")
            }
        }
        
        func deleteNoteAtIndexPath(_ indexPath: IndexPath) {
            let noteToDelete = fetchedNotes[indexPath.section]
            context.delete(noteToDelete)
            fetchedNotes.remove(at: indexPath.section)
            
            do {
                try context.save()
                tableView.beginUpdates()
                tableView.deleteSections([indexPath.section], with: .automatic)
                tableView.endUpdates()
            } catch {
                print("Not silme hatası: \(error)")
            }
        }
        
        //MARK: setup Fonksiyonları
        
        func setupTableView() {
            view.addSubview(tableView)
            tableView.dataSource = self
            tableView.delegate = self
            tableView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
                tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 5),
                tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50),
                tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5)
            ])
            tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
        }
        
        func setupCreateNoteButton() {
            view.addSubview(createNoteButton)
            let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 45, weight: .regular, scale: .default)
            // "+" işaretini oluşturuyoruz ve konfigürasyonunu ekliyoruz
            let plusSymbol = UIImage(systemName: "plus", withConfiguration: symbolConfiguration)
            createNoteButton.setImage(plusSymbol, for: .normal)
            createNoteButton.tintColor = .systemYellow // "+" işaretinin rengini sarı yapıyoruz
            
            // Buton için içi boş çember oluşturuyoruz
            createNoteButton.backgroundColor = .clear // Butonun arka planını transparan yapıyoruz
            createNoteButton.layer.cornerRadius = 35 // Butonun yarıçapını ayarlıyoruz
            createNoteButton.layer.borderWidth = 2 // Çerçeve genişliği
            createNoteButton.layer.borderColor = UIColor.systemYellow.cgColor
            
            createNoteButton.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                createNoteButton.heightAnchor.constraint(equalToConstant: 70),
                createNoteButton.widthAnchor.constraint(equalToConstant: 70),
                createNoteButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20),
                createNoteButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -55)
            ])
            createNoteButton.addTarget(self, action: #selector(createNoteButtonTapped), for: .touchUpInside)
        }
    
    
        
        func setupTitleLabel() {
            titleLabel.text = "TextCrypt"
            titleLabel.font = UIFont(name: "TimesNewRomanPS-BoldMT", size: 27)
            titleLabel.textColor = .white
            navigationItem.titleView = titleLabel
        }
        
        func setupUIBasedOnSwitch(switchValue: Bool) {
            if switchValue {
                view.backgroundColor = .white
                tableView.backgroundColor = .white
                randomLabel.textColor = .black
                titleLabel.textColor = .black
              //  randomColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1)
                randomColor = .white
            } else {
                view.backgroundColor = .black
                tableView.backgroundColor = .black
                randomLabel.textColor = .white
                titleLabel.textColor = .white
              //  randomColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1)
                randomColor = .black
            }
        }
        
        private func resetCellSize(at indexPath: IndexPath) {
            if let cell = tableView.cellForRow(at: indexPath) {
                UIView.animate(withDuration: 0.2) {
                    cell.transform = CGAffineTransform.identity
                }
            }
        }
        
        private func resetButtonSize(){
            UIView.animate(withDuration: 0.1) {
                self.createNoteButton.transform = CGAffineTransform.identity
            }
        }
        
        // MARK: @objc fonksiyonları
            
        @objc func optionsButtonTapped() {
            let settingsVC = SettingsController()
            settingsVC.modalPresentationStyle = .fullScreen
            settingsVC.mainVC = self
            present(settingsVC, animated: true)
        //    settingsVC.dismissAction = { [weak self] in }
            
            }
    
    
        
        @objc func handleLongPressButton(gesture: UILongPressGestureRecognizer) {
            if gesture.state == .began {
                UIView.animate(withDuration: 0.1) {
                    self.createNoteButton.transform = CGAffineTransform(scaleX: 0.90, y: 0.90)
                }
            } else if gesture.state == .ended || gesture.state == .cancelled{
                resetButtonSize()
            }
        }
        
        @objc func handleLongPressCell(gesture: UILongPressGestureRecognizer) {
            let point = gesture.location(in: tableView)
            if let indexPath = tableView.indexPathForRow(at: point) {
                switch gesture.state {
                case .began:
                    if let cell = tableView.cellForRow(at: indexPath) {
                            UIView.animate(withDuration: 0.1) {
                                cell.transform = CGAffineTransform(scaleX: 0.97, y: 0.97)
                        }
                    }
                case .ended, .changed:
                    resetCellSize(at: indexPath)
                default:
                    break
                }
            }
        }
    
        
    
        // MARK: tavleView ayarları
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
        
        func numberOfSections(in tableView: UITableView) -> Int {
            return fetchedNotes.count
        }
        
        func didRequestDelete(_ cell: TableViewCell) {
            guard let indexPath = tableView.indexPath(for: cell) else {return}
            self.deleteNoteAtIndexPath(indexPath)
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as? TableViewCell else {
                return UITableViewCell()
            }
            cell.delegate = self
            cell.contentView.backgroundColor = self.randomColor
            cell.contentView.layer.borderColor = self.createNoteButton.tintColor.cgColor
            cell.titleLabel.textColor = self.randomLabel.textColor
            cell.noteLabel.textColor = self.randomLabel.textColor
            cell.deleteButton.backgroundColor = self.createNoteButton.tintColor
    
            let note = fetchedNotes[indexPath.section]
            cell.configure(with: note)
            
            return cell
        }
        
        func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
            let view = UIView()
            view.backgroundColor = .clear
            return view
        }
    
        func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
            return cellSpacing
        }
    
        // MARK: didSelectRowAt
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.reloadRows(at: [indexPath], with: .none)
            
            if let cell = tableView.cellForRow(at: indexPath) {
                let animation = CABasicAnimation(keyPath: "transform.scale")
                animation.fromValue = 1.0
                animation.toValue = 0.92
                animation.duration = 0.10
                animation.autoreverses = true
                animation.repeatCount = 1
    
                cell.layer.add(animation, forKey: "bounce")
            }
            
            let noteDetailVC = NoteDetailViewController()
            // Seçilen notu NoteDetailViewController'a geçir
            let selectedNote = fetchedNotes[indexPath.section]
            noteDetailVC.note = selectedNote
            noteDetailVC.noteContent = selectedNote.text
            noteDetailVC.titleContent = selectedNote.title
            noteDetailVC.dateContent = selectedNote.date
            noteDetailVC.timeContent = selectedNote.time
            noteDetailVC.view.backgroundColor = self.view.backgroundColor
            noteDetailVC.textView.backgroundColor = self.view.backgroundColor
            noteDetailVC.titleLabel.textColor = self.randomLabel.textColor
            noteDetailVC.textView.textColor = self.randomLabel.textColor
            noteDetailVC.backMarkItem.tintColor = createNoteButton.tintColor
            noteDetailVC.checkMarkItem.tintColor = createNoteButton.tintColor
            noteDetailVC.redoButton.tintColor = createNoteButton.tintColor
            noteDetailVC.undoButton.tintColor = createNoteButton.tintColor
            noteDetailVC.encryptMarkItem.tintColor = createNoteButton.tintColor
            noteDetailVC.specialButton.backgroundColor = createNoteButton.tintColor
            noteDetailVC.dismissAction = { [weak self] in
                // Kullanıcı notu tamamen silip geri döndüğünde ilgili notu sil
                if let newNote = noteDetailVC.noteContent, newNote.isEmpty,
                   let newTitle = noteDetailVC.titleContent, newTitle.isEmpty {
                    // Not silme fonksiyonunu çağır
                    self?.deleteNoteAtIndexPath(indexPath)
                } else {
                    // Not güncellendiyse veya değişiklik olmadıysa güncellemeleri kaydet
                    if let newNote = noteDetailVC.noteContent, !newNote.isEmpty,
                       let newTitle = noteDetailVC.titleContent, !newTitle.isEmpty {
                        // Yeni bir Core Data nesnesi oluştur ve kaydet
                    }
                    // Notları tekrar çekmek için fetchNotes çağrılabilir
                    self?.fetchNotes()
                }
            }
            
            let navigationController = UINavigationController(rootViewController: noteDetailVC)
            navigationController.modalPresentationStyle = .fullScreen
            present(navigationController, animated: true)
        }
    }
    
    
    

    在此输入

  • 也许可以帮助一个人向他们展示如何转换,然后进行比较。这将是一个答案。这最多是一个评论。

  • @Prog 谢谢!我刚刚学习了 javascript 2 周,想尝试一下自己创建一个小项目!显然我还没准备好,哈哈。我有一个问题,我不太确定我是否理解 if 语句中 \'or\' 的用法。如果问题太明显,再次抱歉

  • @user23321762,如果 currentData 大于 objectData,则 OR year 必须大于 OR month 或 day。如果所有这些都不再存在,则程序继续运行。

  • @user23321762,抱歉我的无礼,但如果我以任何方式帮助了你,你可以通过点击我答案旁边的向上箭头和复选标记来感谢我)

  • 引用 17

    @prog 啊,谢谢,我现在明白了。不过有一个问题,使用你的解决方案,似乎只有第一个日期被重复了三次,而不是检查所有三个日期。你能解释一下我如何检查每个对象内的日期吗?

  • 您的代码中存在太多问题,我甚至不知道从哪里开始!
    这是一个可能的解决方案,你应该研究一下。

    PS:不是接受编程课程的地方。

    const
      menu = 
        [ { id: 1, title: 'title of item one',   date: '22/12/2023' } 
        , { id: 2, title: 'title of item two',   date: '30/01/2024' } 
        , { id: 3, title: 'title of item three', date: '18/04/2025' } 
        ] 
    , now  = new Date()  // = today Date + Hours, minutes, seconds, milliseconds
    , DD   = String( now.getDate()    ).padStart(2, '0') // Numeric values must be replaced by a string 
    , MM   = String( now.getMonth() +1).padStart(2, '0') // with a leading zero for 2 full digits.
    , YYYY = now.getFullYear()
    , currentDate = YYYY + MM + DD // in algebraic order, years come first
      ;
    for (let row of menu) 
      {
      let 
        [dd,mm,yyyy] = row.date.split('/') // values are separated by slashes, not hyphens
      , ymd          = yyyy + mm + dd      // transpose d/m/y to ymd
        ;
      switch ( currentDate.localeCompare(ymd) ) // for String type use localeCompare() method
        {
        case 0:
          console.log("Hurry! Expires TODAY -->", row.date );
          break;
        case 1:
          console.log("Sorry this deal is expired -->", row.date );
          break;
        default: // or -1
          console.log("Expires on " + row.date );
        }
      }
  • 我有一个地图脚本。我有一个字符串,用于显示地图的属性之一。“位置”是 {lat:纬度值,lng:经度值}。我创建了一个看起来正确的字符串。值...

    我有一个地图脚本。我有一个用于显示地图的属性字符串。“位置”是 {lat:纬度值,lng:经度值}。
    我创建了一个看起来正确的字符串。变量显示为变量名“position”。我尝试使用 parse.JSON 进行转换,但它仍然只显示为变量名。我尝试了以下方法:var position = JSON.parse('{\'lat:\' + latitude + \',lng:\' + longitude }');但是,显示的是单词“position”,而不是值。为什么这不起作用?感谢您的帮助

  • 引用 20

    您尝试在方法中使用字符串连接, JSON.parse 但在解析之前未正确将字符串格式化为有效的 JSON。动态创建 JSON 字符串的正确方法是将变量与字符串正确连接,确保整个字符串是有效的 JSON。然后, JSON.parse() 可用于将此字符串转换为对象。

    但是,对于您来说,您不需要进行 JSON 转换过程,因为纬度和经度的值已经可用。您可以直接将纬度和经度值分配给对象,如下所示:

    var position = {lat: parseFloat(latitude), lng: parseFloat(longitude)};
    

    确保纬度和经度要么是可以解析为浮点数的字符串,要么已经是数字。 parseFloat() 这里使用该函数来确保纬度和经度值被视为浮点数,这是纬度和经度的正确格式。

    这种方法比创建 JSON 字符串并解析它更高效、更直接,特别是因为您已经在 J​​avaScript 中工作并且不需要序列化/反序列化数据。

返回
作者最近主题: