ios - 使用 UITableViewAutomaticDimension 制作带有嵌入式 UICollectionView 的 UITableView

标签 ios swift uitableview uicollectionview

我想创建一个带有标题标签的 UITableView 和使用 UITableViewAutomaticDimension 嵌入的 UICollectionView(它知道它的大小)和一些图标。问题是 UITableView 在我有 UICollectionView 时计算单元格高度有问题。我必须滚动 UITableView 才能重新计算大小。但即便如此,它也存在高度问题(如果从更大的高度重复使用它就太大了)。最重要的是,UICollectionView 中的图标从一开始就不知道,但它们旨在从服务器加载。

我也曾尝试为 UICollectionView 创建高度约束,但由于与 UIView-Encapsulated-Layout 的冲突,这种方式导致“无法同时满足约束” -Height 和我自己的约束无论如何都被删除了。

我已经创建了一个带有示例项目的 GitHub 存储库(我做的尽可能简单):

https://github.com/piotrros/CollectionViewInTableView

最佳答案

因为你在 cellForRow 中做了很多事情所以它需要时间准备所以当你滚动时它没有正确显示

检查以下内容。

ViewController.swift

在 View 中加载

添加tableView.rowHeight = UITableViewAutomaticDimension

并替换这个方法

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let foo = foos[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell



    cell.titleLabel.text = foo.title
    cell.descriptionLabel.text = foo.description

    self.view.layoutIfNeeded()

    return cell
}

FooTableViewCell.swift

class FooTableViewCell: UITableViewCell {

    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var stackView: UIStackView!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var iconsCollectionView: IconsCollectionView!
    @IBOutlet weak var const_Height_CollectionView: NSLayoutConstraint!


    override func awakeFromNib() {
        iconsCollectionView.translatesAutoresizingMaskIntoConstraints = false
        iconsCollectionView.initFlowLayout(superviewWidth: self.frame.width)
        iconsCollectionView.loadIconsSync()
        iconsCollectionView.setNeedsLayout()

    }
}

我已经从你的 Storyboard中删除了 StackView,只给出了前导、尾随、顶部和底部约束(没有什么复杂的)

enter image description here

这里是输出

enter image description here

希望对你有帮助

编辑/更新

您的演示项目中有很多问题。 我对您的演示项目做了很多更改。

XML 复制并粘贴到 Storyboard中。

不要忘记连接高度限制

这是完整的 Storyboard XML

 <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="CollectionViewInTableView" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="196" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ZhZ-if-Yia">
                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                <prototypes>
                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="196" id="1WO-2S-MI9" customClass="FooTableViewCell" customModule="CollectionViewInTableView" customModuleProvider="target">
                                        <rect key="frame" x="0.0" y="28" width="375" height="196"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="1WO-2S-MI9" id="2lF-aM-Z2U">
                                            <rect key="frame" x="0.0" y="0.0" width="375" height="195.5"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vs4-91-woo">
                                                    <rect key="frame" x="8" y="8" width="359" height="20.5"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Description" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lD2-bR-lnm">
                                                    <rect key="frame" x="8" y="36.5" width="359" height="20.5"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="6sQ-gf-Y6x" customClass="IconsCollectionView" customModule="CollectionViewInTableView" customModuleProvider="target">
                                                    <rect key="frame" x="8" y="65" width="359" height="92.5"/>
                                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                    <constraints>
                                                        <constraint firstAttribute="height" relation="greaterThanOrEqual" priority="750" constant="88" id="f9g-Du-pYg"/>
                                                    </constraints>
                                                    <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Nts-Lf-FPD">
                                                        <size key="itemSize" width="50" height="50"/>
                                                        <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                                        <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                                        <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                                    </collectionViewFlowLayout>
                                                    <cells>
                                                        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="item" id="8gX-Q1-0jG" customClass="BarCollectionViewCell" customModule="CollectionViewInTableView" customModuleProvider="target">
                                                            <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                                            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
                                                                <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                                                <autoresizingMask key="autoresizingMask"/>
                                                                <subviews>
                                                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="6cf-uD-BQl">
                                                                        <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                                                    </imageView>
                                                                </subviews>
                                                            </view>
                                                            <constraints>
                                                                <constraint firstAttribute="bottom" secondItem="6cf-uD-BQl" secondAttribute="bottom" id="0c3-ug-8tN"/>
                                                                <constraint firstItem="6cf-uD-BQl" firstAttribute="top" secondItem="8gX-Q1-0jG" secondAttribute="top" id="9xW-dN-c0m"/>
                                                                <constraint firstItem="6cf-uD-BQl" firstAttribute="leading" secondItem="8gX-Q1-0jG" secondAttribute="leading" id="dT6-RU-eE4"/>
                                                                <constraint firstAttribute="trailing" secondItem="6cf-uD-BQl" secondAttribute="trailing" id="nnz-oA-GgP"/>
                                                            </constraints>
                                                            <connections>
                                                                <outlet property="iconImageView" destination="6cf-uD-BQl" id="lFo-SS-Ego"/>
                                                            </connections>
                                                        </collectionViewCell>
                                                    </cells>
                                                </collectionView>
                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sXa-Mn-xxW">
                                                    <rect key="frame" x="8" y="165.5" width="359" height="30"/>
                                                    <state key="normal" title="Button"/>
                                                </button>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="sXa-Mn-xxW" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="4ix-8u-0lO"/>
                                                <constraint firstAttribute="bottom" secondItem="sXa-Mn-xxW" secondAttribute="bottom" id="50m-Bv-FF8"/>
                                                <constraint firstAttribute="trailing" secondItem="sXa-Mn-xxW" secondAttribute="trailing" constant="8" id="8UW-vI-hge"/>
                                                <constraint firstItem="6sQ-gf-Y6x" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="9ht-Ez-lJX"/>
                                                <constraint firstAttribute="trailing" secondItem="vs4-91-woo" secondAttribute="trailing" constant="8" id="NOH-if-o7C"/>
                                                <constraint firstItem="lD2-bR-lnm" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="S2D-Kj-5Og"/>
                                                <constraint firstItem="vs4-91-woo" firstAttribute="leading" secondItem="2lF-aM-Z2U" secondAttribute="leading" constant="8" id="atk-7U-Mrw"/>
                                                <constraint firstAttribute="trailing" secondItem="6sQ-gf-Y6x" secondAttribute="trailing" constant="8" id="bfY-uh-Su2"/>
                                                <constraint firstItem="vs4-91-woo" firstAttribute="top" secondItem="2lF-aM-Z2U" secondAttribute="top" constant="8" id="gYO-XW-lmk"/>
                                                <constraint firstAttribute="trailing" secondItem="lD2-bR-lnm" secondAttribute="trailing" constant="8" id="pkH-Pf-xE1"/>
                                                <constraint firstItem="sXa-Mn-xxW" firstAttribute="top" secondItem="6sQ-gf-Y6x" secondAttribute="bottom" constant="8" id="w2O-4g-q6B"/>
                                                <constraint firstItem="6sQ-gf-Y6x" firstAttribute="top" secondItem="lD2-bR-lnm" secondAttribute="bottom" constant="8" id="xky-sw-IcM"/>
                                                <constraint firstItem="lD2-bR-lnm" firstAttribute="top" secondItem="vs4-91-woo" secondAttribute="bottom" constant="8" id="yG3-dE-CjF"/>
                                            </constraints>
                                        </tableViewCellContentView>
                                        <connections>
                                            <outlet property="const_Height_CollectionView" destination="f9g-Du-pYg" id="gw7-9T-hiU"/>
                                            <outlet property="descriptionLabel" destination="lD2-bR-lnm" id="M4K-k5-6LN"/>
                                            <outlet property="iconsCollectionView" destination="6sQ-gf-Y6x" id="FO2-dP-VNH"/>
                                            <outlet property="titleLabel" destination="vs4-91-woo" id="HHy-1V-bTW"/>
                                        </connections>
                                    </tableViewCell>
                                </prototypes>
                            </tableView>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="ZhZ-if-Yia" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="J8c-wQ-FxB"/>
                            <constraint firstItem="ZhZ-if-Yia" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="KCX-nj-zXy"/>
                            <constraint firstItem="ZhZ-if-Yia" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="QMU-w2-uUY"/>
                            <constraint firstItem="ZhZ-if-Yia" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="yx7-yg-aqC"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                    </view>
                    <connections>
                        <outlet property="tableView" destination="ZhZ-if-Yia" id="WdR-nu-gjc"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="117.59999999999999" y="118.29085457271366"/>
        </scene>
    </scenes>
</document>

FOOTableviewCell.swift

protocol TableViewDelegate {
    func cellTapped (for:FooTableViewCell)
}


class FooTableViewCell: UITableViewCell {


    static let singleCellHeight = 88;

    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var iconsCollectionView: IconsCollectionView!
    @IBOutlet weak var const_Height_CollectionView: NSLayoutConstraint!

    var delegateCollection : TableViewDelegate?
    var bars:[Bar] = [] {
        didSet {
            self.iconsCollectionView.reloadData()
            iconsCollectionView.setNeedsLayout()
            self.layoutIfNeeded()
            const_Height_CollectionView.constant =  iconsCollectionView.contentSize.height
            self.layoutIfNeeded()
        }
    }

    override func awakeFromNib() {
        iconsCollectionView.translatesAutoresizingMaskIntoConstraints = false
        iconsCollectionView.initFlowLayout(superviewWidth: self.frame.width)
        iconsCollectionView.setNeedsLayout()
        iconsCollectionView.dataSource = self
        iconsCollectionView.delegate = self
        const_Height_CollectionView.constant =  iconsCollectionView.contentSize.height
        self.layoutIfNeeded()
        self.setNeedsLayout()
    }

    func cellTapped () {
        iconsCollectionView.setNeedsLayout()
        self.layoutIfNeeded()
        self.setNeedsLayout()

        const_Height_CollectionView.constant =  iconsCollectionView.contentSize.height

        self.delegateCollection?.cellTapped(for: self)

    }

}

extension FooTableViewCell : UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return bars.count + 1
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "item", for: indexPath) as! BarCollectionViewCell

        let row = indexPath.row
        if(row >= bars.count) {
            cell.iconImageView.image = UIImage(named: "add.png")
            return cell
        } else {
            let bar = bars[row]
            cell.iconImageView.image = UIImage(named: bar.imageName)
            print(bar.imageName)

            return cell
        }

    }

}

extension FooTableViewCell : UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //deselectItem(at: indexPath, animated: true)
        if(indexPath.row >= bars.count) { //it's a plus button
            self.delegateCollection?.cellTapped(for: self)
        }
    }
}

IconCollectionView.swift

import UIKit



class IconsCollectionView: DynamicCollectionView {


    var columnLayout:ColumnFlowLayout?



    override func awakeFromNib() {
    }

    func initFlowLayout(superviewWidth:CGFloat) {
        let layout = ColumnFlowLayout(
            cellsPerRow: 4,
            superviewWidth: superviewWidth,
            minimumInteritemSpacing: 0,
            minimumLineSpacing: 0,
            sectionInset: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        )
        columnLayout = layout
        collectionViewLayout = layout
    }
}

ViewController.Swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    var foos:[Foo] = []

    var bars:[[Bar]] = [[]]

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self
        tableView.estimatedRowHeight = 188
        tableView.rowHeight = UITableViewAutomaticDimension

        for i in stride(from: 1, to: 10, by: 1) {
            let foo = Foo()
            foo.title = "Item \(i)"
            foo.description = "Description \(i)"
            foos.append(foo)
        }
        bars.removeAll()
        for _ in 0 ..< foos.count {
            bars.append(self.loadIconsSync())
        }
    }

    func loadIconsSync() -> [Bar] {

        var barObjects :[Bar] = []

        let iconsCount = Utils.rnd(3, 8)
        for _ in stride(from: 1, to: iconsCount, by: 1) {
            barObjects.append(self.getRandomItem())
        }

        return barObjects
    }

    func getRandomItem() -> Bar {
        let randomIndex = Utils.rnd(1, 10)
        let bar = Bar()
        bar.imageName = "icon_\(randomIndex).png"
        return bar
    }

}

extension ViewController : UITableViewDataSource,UITableViewDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let foo = foos[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell

        var bar = bars[indexPath.row]
        cell.bars = bar

        cell.titleLabel.text = foo.title
        cell.descriptionLabel.text = foo.description
        cell.delegateCollection = self
        self.view.layoutIfNeeded()
        cell.const_Height_CollectionView.constant =  cell.iconsCollectionView.contentSize.height
        self.view.layoutIfNeeded()

        return cell
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return foos.count
    }

}

extension ViewController : TableViewDelegate {
    func cellTapped(for obj: FooTableViewCell) {
        if let indexPath = tableView.indexPath(for: obj) {
            bars[indexPath.row].append(getRandomItem())
            self.tableView.beginUpdates()
            self.tableView.reloadRows(at: [indexPath], with: .automatic)
            self.tableView.endUpdates()
        }
    }

}

输出

enter image description here

编辑/更新 2

我不知道方向支持和 ipad 支持。

现在,当方向发生变化时,我们必须重新布局 Collection View 。

逻辑是

项目总数 + 1(+ 1 因为那个加号图标)

项目大小 *(项目总数/3)。四舍五入

假设你有 7 个项目

因此项目大小为 93(每行)* ( 8/3).rounded = 279

因此在这里您需要根据您对 iPad 和横向模式的要求管理一些硬编码值。 现在我正在考虑每行 3 个对象,与 iPhone 设计相同。

这里 Hardcoded cell number 是 3 你可以自己管理。

第一步:

在viewContorller.swift中添加Following方法

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        super.viewWillTransition(to: size, with: coordinator)
            self.tableView.beginUpdates()
            self.tableView.reloadData()
            self.tableView.endUpdates()
        }

替换 cellForRowAtIndexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let foo = foos[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FooTableViewCell

        cell.iconsCollectionView.initFlowLayout(superviewWidth: self.tableView.frame.width)

        let bar = bars[indexPath.row]
        cell.bars = bar

        cell.titleLabel.text = foo.title
        cell.descriptionLabel.text = foo.description
        cell.delegateCollection = self
        self.view.layoutIfNeeded()

        let items:CGFloat = CGFloat(bar.count + 1)
        let value = (items / 3.0).rounded(.awayFromZero)
        cell.const_Height_CollectionView.constant =  CGFloat((cell.iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)

        self.view.layoutIfNeeded()
        cell.iconsCollectionView.setNeedsLayout()
        return cell
    }

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if let  footCell =  cell as?  FooTableViewCell {
            footCell.const_Height_CollectionView.constant = footCell.iconsCollectionView.contentSize.height
            self.view.layoutIfNeeded()

        }
    }

在 TableviewCell 中

var bars:[Bar] = [] {
        didSet {
            self.iconsCollectionView.reloadData()
            iconsCollectionView.setNeedsLayout()
            self.layoutIfNeeded()

            let items:CGFloat = CGFloat(bars.count + 1)
            let value = (items / 3.0).rounded(.awayFromZero)

            const_Height_CollectionView.constant =  CGFloat((iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)

            self.layoutIfNeeded()
        }
    }

func cellTapped () {
        iconsCollectionView.setNeedsLayout()
        self.layoutIfNeeded()
        self.setNeedsLayout()
        let items:CGFloat = CGFloat(bars.count + 1)
        let value = (items / 3.0).rounded(.awayFromZero)
        const_Height_CollectionView.constant =  CGFloat((iconsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize.height * value)
        self.delegateCollection?.cellTapped(for: self)

    }

关于ios - 使用 UITableViewAutomaticDimension 制作带有嵌入式 UICollectionView 的 UITableView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48093595/

相关文章:

ios - 在用户无法访问的地方快速保存图片

iphone - selectall uitextfield 并不总是全选

Javascript 从 swift 中获取值(value)

ios - Realm 因 RLMException : object has been deleted or invalidated 崩溃

ios - 在 Controller Swift 之间传递对象

ios - 使用 Xcode Instruments 查看指针处的非僵尸对象历史记录

ios - 如何制作DateComponentsFormatter.string的第一个字(来自:)'s result capitalised?

swift - 字典初始化(分组 :by:), 2 级 - 简化代码

ios - 如何对齐表格 View 行中的自定义单元格-左或右-IOS

ios - 当选择 UITableViewCell 时,UIImageView 会更改其位置