UIViewController of lifecycle

博客围绕UIViewController的生命周期展开,虽暂无具体内容,但可知聚焦于该视图控制器在不同阶段的状态变化等信息技术相关内容。
为什么一开始进入到默认event.view页面就会打印viewWillAppear false日志,然后切换到device alert就会viewWillDisappear false,而在custom和device切换没有日志,event页面是不是切换有逻辑问题?且我并没有打印出这样的日志,系统还会自动打印吗?// // EventCenterViewController.swift import TPBMDesignKit // MARK: - eventcenter主控制器 class TPGuardEventCenterController: TPHomeBaseViewController{ //侧边栏controller private let eventCenterSidebarController = TPGuardSidebarController() private let eventCenterSplitView: TPGuardEventCenterSpliteView = TPGuardEventCenterSpliteView() private var isIniteventCenterPlayerSplitView: Bool = false // 侧边栏是否已收起 private var isSidebarCollapsed :Bool = false // 右侧三个子页面controller private let eventCenterRightView = NSView() private let eventController = TPGuardEventController() private let customAlertController = TPGuardCustomAlertController() private let deviceAlertController = TPGuardDeviceAlertController() //侧边栏的导航栏 private let eventCenterSidebarScrollView : NSScrollView = NSScrollView() private let eventCenterSidebarOutlineView : TPGuardOutlineView = TPGuardOutlineView() //侧边栏收起按钮 private let sidebarButton : TPBButton = TPBButton() //侧边栏的item private var sidebarItems: [SidebarItem] = [] //第一次加载进内存时候 override func viewDidLoad() { super.viewDidLoad() // Do view setup here. } override func setupSubviews() { super.setupSubviews() // MARK: - 主界面splitView分割 /*split添加调用 addArrangedSubview 不仅添加了视图,还让 NSSplitView 知道:“这个视图是我要管理的一个面板”,然后根据 arrangedSubviews 的顺序来决定左右或上下结构*/ eventCenterSplitView.addArrangedSubview(eventCenterSidebarController.view) eventCenterSplitView.addArrangedSubview(eventCenterRightView) //三个右侧页面添加到view [eventController.view, customAlertController.view, deviceAlertController.view].forEach{ eventCenterRightView.addSubview($0) $0.translatesAutoresizingMaskIntoConstraints=false $0.snp.makeConstraints{make in make.edges.equalToSuperview()} } // //默认显示event页面 print("默认显示event页面") switchRightView(to: eventController.view) //设置代理 eventCenterSplitView.delegate = self //分割线设置+风格 eventCenterSplitView.isVertical = true eventCenterSplitView.dividerStyle = .thin // 异步设置初始宽度(确保布局已完成) DispatchQueue.main.async { [weak self] in guard let self = self else { return } let initialWidth: CGFloat = self.isSidebarCollapsed ? 48 : 160 self.eventCenterSplitView.setPosition(initialWidth, ofDividerAt: 0) // 根据目标宽度设置状态 self.isSidebarCollapsed = false } // 将 splitView 添加到主视图 view.addSubview(eventCenterSplitView) // MARK: - 侧边栏层级+按钮设置 // 添加收起按钮、配置 TPBButton 样式 sidebarButton.iconImage = .eventCenterSidebarButton sidebarButton.fillColor = .clear //代理 sidebarButton.target = self sidebarButton.action = #selector(hideSidebar) //将侧边栏按钮添加到侧边栏视图 eventCenterSidebarController.view.addSubview(sidebarButton) //将 eventCenterSidebarOutlineView 设置为滚动视图的“文档内容视图”(即可滚动区域的内容) eventCenterSidebarScrollView.documentView = eventCenterSidebarOutlineView //设置滚动视图背景颜色为深灰色(接近黑色) eventCenterSidebarScrollView.backgroundColor = NSColor(hexString: "0x1A1A1A") //关闭系统自动调整内容边距(content insets) eventCenterSidebarScrollView.automaticallyAdjustsContentInsets = false //启用 Auto Layout 布局方式、允许使用约束(constraints)来定位该视图 eventCenterSidebarScrollView.translatesAutoresizingMaskIntoConstraints = false //documentView添加水平方向约束让documentView的左右边缘与scrollView 对齐 eventCenterSidebarScrollView.documentView?.snp.remakeConstraints({ make in make.leading.trailing.equalTo(eventCenterSidebarScrollView) }) eventCenterSidebarOutlineView.backgroundColor = NSColor(hexString: "0x1A1A1A") //delegate 管“怎么展示”,dataSource 管“展示什么”。 eventCenterSidebarOutlineView.delegate = self eventCenterSidebarOutlineView.dataSource = self eventCenterSidebarOutlineView.tpGuardDelegate = self //启用自动行高(Auto Sizing Rows)。 eventCenterSidebarOutlineView.usesAutomaticRowHeights = true //禁用列的自动调整大小行为。默认情况下,AppKit 会尝试平均分配或按内容调整列宽。 eventCenterSidebarOutlineView.columnAutoresizingStyle = .noColumnAutoresizing //关闭选中项的高亮样式。原生默认是蓝色或灰色背景高亮。 eventCenterSidebarOutlineView.selectionHighlightStyle = .none //移除表头(Header View)。默认 NSTableView 顶部有一栏用于显示列标题。 eventCenterSidebarOutlineView.headerView = nil //禁用“轮廓列”(Outline Column)的自动缩放。在 NSOutlineView 中,“outline column”是显示层级结构的那一列(带展开箭头的那列)。 eventCenterSidebarOutlineView.autoresizesOutlineColumn = false //允许子视图(cell 内部的 subviews)随容器自动调整大小。这会影响单元格内部控件是否跟随表格宽度拉伸。 eventCenterSidebarOutlineView.autoresizesSubviews = true //启用 Core Animation Layer(即开启图层支持)。 eventCenterSidebarOutlineView.wantsLayer = true eventCenterSidebarOutlineView.layer?.borderColor = NSColor(hexString: "0xFFFFFF").withAlphaComponent(0.1).cgColor eventCenterSidebarOutlineView.layer?.borderWidth = 1.0 //注册支持接收某种拖拽类型的数据。 eventCenterSidebarOutlineView.registerForDraggedTypes([.dragOutlineItem]) //设置当前视图为拖拽源(source)时允许的操作类型。 eventCenterSidebarOutlineView.setDraggingSourceOperationMask(NSDragOperation.every, forLocal: true) //设置单元格之间的间距 eventCenterSidebarOutlineView.intercellSpacing = NSSize(width: view.bounds.width, height: 30.0) //创建并添加一列到表格中。 let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Column")) eventCenterSidebarOutlineView.addTableColumn(column) // eventCenterSidebarOutlineView.onDoubleClick = { [weak self] item in // if let device = item as? TPGuardDeviceItem, let self { // if device.deviceType == .IPC { // self.selectDevice(for: device) // } // } // } //允许“轮廓列”(Outline Column)根据父视图的大小变化自动调整宽度。 eventCenterSidebarOutlineView.autoresizesOutlineColumn = true //设置每一级子节点相对于父节点的缩进像素值(indentation),这里设为 0 像素。 eventCenterSidebarOutlineView.indentationPerLevel = 0 //将scrollView添加到侧边栏视图 eventCenterSidebarController.view.addSubview(eventCenterSidebarScrollView) eventCenterSidebarOutlineView.target = self eventCenterSidebarOutlineView.action = #selector(handleSidebarClick) } //添加约束 override func makeConstraints() { super.makeConstraints() // 让 eventCenterPlayerSplitView 的 上边、左边、下边、右边 都等于父视图 view 的对应边缘,也就是让这个 splitView 填满整个父视图的客户区(不包括窗口标题栏等系统区域)。 eventCenterSplitView.snp.makeConstraints { make in make.top.leading.bottom.trailing.equalTo(view) } // 添加侧边栏按钮的约束 sidebarButton.snp.makeConstraints { make in make.leading.equalToSuperview().offset(15) make.top.equalToSuperview().offset(15) make.size.equalTo(CGSize(width: 18, height: 18)) } //scrollview添加约束(与侧边栏按钮拉开了距离) eventCenterSidebarScrollView.snp.makeConstraints { make in make.top.equalTo(sidebarButton.snp.bottom).offset(8) make.leading.trailing.bottom.equalToSuperview() } } // MARK: - 初始化数据(后续需要介入拉取未读数) override func setupInitialData() { super.setupInitialData() // 全部事件 let events = SidebarItem(title: "Events", iconImage: .sidebarChooseButton, showsBadge: false) // 自定义告警 let customAlerts = SidebarItem( title: "Custom Alerts", iconImage: .sidebarChooseButton, children: [ SidebarItem( title: "My Alerts", iconImage: .sidebarChooseButton, children: [ SidebarItem(title: "Alert 1", iconImage: .sidebarChooseButton, showsBadge: true, unreadCount: 2), SidebarItem(title: "Alert 2", iconImage: .sidebarChooseButton, showsBadge: true, unreadCount: 1) ], showsBadge: false ), SidebarItem( title: "Shared Alerts", iconImage: .sidebarChooseButton, children: [ SidebarItem(title: "Alert 3", iconImage: .sidebarChooseButton, showsBadge: true, unreadCount: 3) ], showsBadge: false ) ], showsBadge: true, unreadCount: 99 ) // 设备告警 let deviceAlerts = SidebarItem(title: "Device Alerts", iconImage: .sidebarChooseButton, showsBadge: true, unreadCount: 3) sidebarItems = [events, customAlerts, deviceAlerts] } //绑定侧边栏的按钮事件(收起+拉伸) override func bindActions() { super.bindActions() } //侧边栏收起方法 @objc func hideSidebar() { let sidebarIndex = 0 let expandWidth : CGFloat = 160 let collapsedWidth : CGFloat = 48 //当侧边栏收起时 if isSidebarCollapsed{ //收起---展开 NSAnimationContext.runAnimationGroup{ context in context.duration = 0.3 // Set the duration of the animation self.eventCenterSplitView.setPosition(expandWidth, ofDividerAt: sidebarIndex) } }else { //展开--收起 NSAnimationContext.runAnimationGroup{ context in context.duration = 0.3 // Set the duration of the animation self.eventCenterSplitView.setPosition(collapsedWidth, ofDividerAt: sidebarIndex) } } isSidebarCollapsed.toggle() } } // MARK: -侧边栏Controller class class TPGuardSidebarController:TPBaseViewController{ override func viewDidLoad() { super.viewDidLoad() // Do view setup here. view.wantsLayer = true view.layer?.backgroundColor = NSColor.tpBackground.cgColor; } } // MARK: -侧边栏Controller扩展 extension TPGuardEventCenterController: NSSplitViewDelegate { //subview 这个子视图是否允许被折叠(即宽度/高度缩小到 0)?” func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool { return false } func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { return 48 } func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { return 160 } //“当用户拖动分隔条时,询问代理:是否允许系统自动调整 view 这个子视图的大小?” func splitView(_ splitView: NSSplitView, shouldAdjustSizeOfSubview view: NSView) -> Bool { return false } // func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool { // return deviceListHasHidden // } // func splitView(_ splitView: NSSplitView, effectiveRect proposedEffectiveRect: NSRect, forDrawnRect drawnRect: NSRect, ofDividerAt dividerIndex: Int) -> NSRect { // return deviceListHasHidden ? NSRect.zero : proposedEffectiveRect // } // func splitViewWillResizeSubviews(_ notification: Notification) { // if deviceListViewController.view.frame.size.width > 500 { // deviceListViewController.view.frame.size = NSSize(width: 500, height: deviceListViewController.view.frame.size.height) // } // } } // MARK: - 事件中心split class class TPGuardEventCenterSpliteView: NSSplitView { override var dividerColor: NSColor { return NSColor.tpSeparator } override var dividerThickness: CGFloat { return 1 } } // MARK: outlineview数据与界面 extension TPGuardEventCenterController: NSOutlineViewDelegate, NSOutlineViewDataSource, TPGuardOutlineViewDelegate { func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { guard let sidebarItem = item as? SidebarItem else { return sidebarItems.count } return sidebarItem.children?.count ?? 0 } func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { guard let sidebarItem = item as? SidebarItem else { return false } return sidebarItem.children?.isEmpty == false } func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { guard let sidebarItem = item as? SidebarItem else { return sidebarItems[index] } return sidebarItem.children![index] } func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { guard let sidebarItem = item as? SidebarItem else { return nil } //唯一标记一种类型的表格单元格(cell)实现 NSOutlineView 或 NSTableView 的 cell 复用机制 let identifier = NSUserInterfaceItemIdentifier("SidebarCell") //尝试从复用池中获取一个已经存在的、可重用的单元格 var sidebarCell = outlineView.makeView(withIdentifier: identifier, owner: self) as? NSTableCellView if sidebarCell == nil { sidebarCell = NSTableCellView() sidebarCell?.identifier = identifier // icon let sidebarImageView = NSImageView() sidebarImageView.translatesAutoresizingMaskIntoConstraints = false sidebarCell?.addSubview(sidebarImageView) sidebarImageView.tag = 100 sidebarImageView.snp.makeConstraints { make in make.leading.equalToSuperview().offset(0) make.centerY.equalToSuperview() make.width.height.equalTo(18) } // title let sidebarTextLabel = NSTextField(labelWithString: "") sidebarTextLabel.translatesAutoresizingMaskIntoConstraints = false sidebarTextLabel.textColor = .white // sidebarTextLabel.font = NSFont.systemFont(ofSize: 12) sidebarCell?.addSubview(sidebarTextLabel) sidebarTextLabel.tag = 101 sidebarTextLabel.snp.makeConstraints { make in make.leading.equalTo(sidebarImageView.snp.trailing).offset(8) make.centerY.equalToSuperview() } // unread count // let sidebarBadgeWidth: CGFloat = 20; // let sidebarBadgeHeigth: CGFloat = 14; // let sidebarBadgeLabel = TPBLabel(); // sidebarBadgeLabel.textColor = .white; // sidebarBadgeLabel.wantsLayer = true; // sidebarBadgeLabel.layer?.backgroundColor = NSColor.red.cgColor; // sidebarBadgeLabel.textAlignment = .center; // sidebarBadgeLabel.layer?.cornerRadius = (sidebarBadgeHeigth - 2) / 2; // sidebarBadgeLabel.layer?.masksToBounds = true; // sidebarBadgeLabel.layer?.borderWidth = 1.0; // sidebarBadgeLabel.layer?.borderColor = NSColor.red.cgColor; // unread count let sidebarBadgeLabel = NSTextField(labelWithString: "") sidebarBadgeLabel.translatesAutoresizingMaskIntoConstraints = false sidebarBadgeLabel.wantsLayer = true sidebarBadgeLabel.layer?.backgroundColor = NSColor.systemRed.cgColor sidebarBadgeLabel.layer?.cornerRadius = 6 sidebarBadgeLabel.textColor = .white sidebarBadgeLabel.alignment = .center sidebarBadgeLabel.font = NSFont.systemFont(ofSize: 10) sidebarCell?.addSubview(sidebarBadgeLabel) sidebarBadgeLabel.tag = 102 sidebarBadgeLabel.snp.makeConstraints { make in make.leading.equalTo(sidebarTextLabel.snp.trailing).offset(8) make.centerY.equalTo(sidebarTextLabel.snp.centerY)//对齐文字 make.width.greaterThanOrEqualTo(16) make.height.equalTo(16) } } if let sidebarImageView = sidebarCell?.viewWithTag(100) as? NSImageView { sidebarImageView.image = sidebarItem.iconImage } if let sidebarTextLabel = sidebarCell?.viewWithTag(101) as? NSTextField { sidebarTextLabel.stringValue = sidebarItem.title } if let sidebarBadgeLabel = sidebarCell?.viewWithTag(102) as? NSTextField { if sidebarItem.showsBadge, let unreadCount = sidebarItem.unreadCount, unreadCount > 0 { sidebarBadgeLabel.isHidden = false if unreadCount >= 99 { sidebarBadgeLabel.stringValue = "\(unreadCount)+" }else{ sidebarBadgeLabel.stringValue = "\(unreadCount)" } } else { sidebarBadgeLabel.isHidden = true } } return sidebarCell } // 缩进 func outlineView(_ outlineView: NSOutlineView, indentationForItem item: Any?) -> CGFloat { return 0 } func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool { guard let sidebarItem = item as? SidebarItem else { return true } // My Alerts / Shared Alerts 这类分组节点不可选中 if let parent = outlineView.parent(forItem: sidebarItem) as? SidebarItem, parent.title == "Custom Alerts", sidebarItem.children?.isEmpty == false { return false } // Custom Alerts 主节点和 alert name 子节点都可以选中 return true } func outlineViewSelectionDidChange(_ notification: Notification) { let selectedRow = eventCenterSidebarOutlineView.selectedRow guard selectedRow >= 0, let selectedItem = eventCenterSidebarOutlineView.item(atRow: selectedRow) as? SidebarItem else { return } for i in 0..<eventCenterSidebarOutlineView.numberOfRows { guard let cell = eventCenterSidebarOutlineView.view(atColumn: 0, row: i, makeIfNecessary: false) as? NSTableCellView, let sidebarItem = eventCenterSidebarOutlineView.item(atRow: i) as? SidebarItem, let titleLabel = cell.viewWithTag(101) as? NSTextField, let iconView = cell.viewWithTag(100) as? NSImageView else { continue } var shouldHighlight = false // Events / Device Alerts 高亮 if sidebarItem == selectedItem && (sidebarItem.title == "Events" || sidebarItem.title == "Device Alerts") { shouldHighlight = true } // Custom Alerts 主节点 + 子节点高亮 if sidebarItem.title == "Custom Alerts" { if selectedItem.title == "Custom Alerts" { shouldHighlight = true } else if let parent = eventCenterSidebarOutlineView.parent(forItem: selectedItem) as? SidebarItem, parent.title == "Custom Alerts", (sidebarItem == parent || sidebarItem == selectedItem) { shouldHighlight = true } } // 更新视觉效果 if shouldHighlight { cell.wantsLayer = true cell.layer?.backgroundColor = NSColor.tpTextHover.cgColor titleLabel.textColor = NSColor.tpStatusGreen iconView.image = .sidebarChoosedButton } else { cell.layer?.backgroundColor = NSColor.clear.cgColor titleLabel.textColor = NSColor.tpTextWhite iconView.image = sidebarItem.iconImage } } } // 切换右侧视图 private func switchRightView(to newView: NSView) { [eventController.view, customAlertController.view, deviceAlertController.view].forEach { $0.isHidden = $0 != newView } } @objc func handleSidebarClick() { let row = eventCenterSidebarOutlineView.clickedRow guard row >= 0, let item = eventCenterSidebarOutlineView.item(atRow: row) as? SidebarItem else { return } switch item.title { case "Events": switchRightView(to: eventController.view) collapseCustomAlertsIfNeeded() case "Device Alerts": switchRightView(to: deviceAlertController.view) collapseCustomAlertsIfNeeded() case "Custom Alerts": // 点击主节点才折叠/展开 if eventCenterSidebarOutlineView.isItemExpanded(item) { eventCenterSidebarOutlineView.collapseItem(item, collapseChildren: true) } else { eventCenterSidebarOutlineView.expandItem(item, expandChildren: true) } switchRightView(to: customAlertController.view) default: // 点击 alert 子节点 if let parent = eventCenterSidebarOutlineView.parent(forItem: item) as? SidebarItem, parent.title == "Custom Alerts" { //switchRightView(to: customAlertController.view) // 不折叠父节点 } } // 统一通过 selectRowIndexes 更新选中 if outlineView(eventCenterSidebarOutlineView, shouldSelectItem: item) { eventCenterSidebarOutlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) // 触发高亮刷新 outlineViewSelectionDidChange(Notification(name: NSOutlineView.selectionDidChangeNotification)) } } private func collapseCustomAlertsIfNeeded() { if let customAlertsItem = sidebarItems.first(where: { $0.title == "Custom Alerts" }) { eventCenterSidebarOutlineView.collapseItem(customAlertsItem, collapseChildren: true) } } }
10-11
internal class TitleView: UIView { private lazy var titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.text = "" titleLabel.textColor = UIColor.tpbTextPrimary titleLabel.font = .boldProjectFont(ofSize: 18.0) titleLabel.lineBreakMode = .byTruncatingTail titleLabel.numberOfLines = 1 return titleLabel }() private lazy var arrowImageView: UIImageView = { let imageView = UIImageView.init(image: TPImageLiteral("devicelist_dropdown_arrow_nor")) return imageView }() lazy var titleLoadingOrgView: SimpleLoadingView = { let view = SimpleLoadingView(frame: CGRectMake(0, 0, 24, 24)) view.isHidden = true return view }() internal var isInExpandStatus: Bool = false fileprivate var isAnimating: Bool = false private var isExccedingWidth: Bool = false public var didClickCallback: ((Bool) -> ())? var titleText: String { get { return titleLabel.text ?? "" } set { titleLabel.text = newValue layoutSubviews() } } override init(frame: CGRect) { super.init(frame: frame) setupViews() bindActions() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupViews() { addSubview(self.titleLabel) addSubview(self.arrowImageView) addSubview(self.titleLoadingOrgView) self.titleLabel.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(6) make.top.bottom.equalToSuperview() make.height.greaterThanOrEqualTo(20) } self.arrowImageView.snp.remakeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(self.titleLabel.snp.trailing) make.size.equalTo(20) make.trailing.equalToSuperview() } } override func layoutSubviews() { super.layoutSubviews() let titleLabelWidth = titleLabel.intrinsicContentSize.width let titleLabelFrameWidth = titleLabel.frame.size.width if titleLabelFrameWidth != 0 && titleLabelWidth > titleLabelFrameWidth { isExccedingWidth = true } } func reloadView() { if isInExpandStatus { self.titleLabel.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(6) make.top.bottom.equalToSuperview() make.height.greaterThanOrEqualTo(20) } self.arrowImageView.snp.remakeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(self.titleLabel.snp.trailing) make.size.equalTo(20) if isExccedingWidth { make.trailing.equalToSuperview().offset(-36) } else { make.trailing.equalToSuperview() } } self.titleLoadingOrgView.snp.remakeConstraints { make in make.leading.equalTo(self.arrowImageView.snp.trailing).offset(12) make.size.equalTo(24) } } else { self.titleLabel.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(6) make.top.bottom.equalToSuperview() make.height.greaterThanOrEqualTo(20) } self.arrowImageView.snp.remakeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(self.titleLabel.snp.trailing) make.size.equalTo(20) make.trailing.equalToSuperview() } } } private func bindActions() { let recognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didClickTitleView)) self.isUserInteractionEnabled = true self.addGestureRecognizer(recognizer) } @objc private func didClickTitleView() { if let didClickCallback { didClickCallback(isInExpandStatus) } } private func rotateArrow(expand: Bool) { let rotation = CABasicAnimation(keyPath: "transform.rotation.z") rotation.fromValue = expand ? 0 : -Double.pi rotation.toValue = expand ? -Double.pi : 0 rotation.duration = 0.3 rotation.fillMode = .forwards rotation.isRemovedOnCompletion = false arrowImageView.layer.add(rotation, forKey: "rotateArrow") } func changeToStatus(expand: Bool) { isInExpandStatus = expand rotateArrow(expand: expand) } }这部分内容呢
11-21
### GIDSignIn 使用指南及 UIViewController 类型相关问题解决 在使用 `GIDSignIn.sharedInstance.signInWithPresentingViewController:self completion:` 方法时,如果出现与 `self` 或 `UIViewController` 类型相关的报错,可能是以下原因导致的。以下是详细的解决方案和使用指南。 #### 1. 确保 `self` 是 `UIViewController` 的实例 该方法要求传入的参数是一个符合 `UIViewController` 类型的对象。如果 `self` 不是 `UIViewController` 或其子类,则会导致编译错误或运行时崩溃。可以通过以下方式验证 `self` 是否为 `UIViewController` 的实例: ```objc if ([self isKindOfClass:[UIViewController class]]) { [GIDSignIn.sharedInstance signInWithPresentingViewController:self completion:^(GIDSignInResult * _Nullable result, NSError * _Nullable error) { if (error == nil && result != nil) { NSLog(@"登录成功"); } else { NSLog(@"登录失败:%@", error.localizedDescription); } }]; } else { NSLog(@"self 必须是 UIViewController 的实例"); } ``` 此代码片段确保了调用方是一个有效的视图控制器[^1]。 #### 2. 设置正确的代理 在调用 `signInWithPresentingViewController:completion:` 方法前,必须确保 `GIDSignIn.sharedInstance.delegate` 已被正确设置为当前视图控制器。例如: ```objc GIDSignIn.sharedInstance.delegate = self; ``` 如果没有正确设置代理,可能导致登录界面无法正常显示或回调失败[^2]。 #### 3. 配置 Info.plist 文件 确保在项目的 `Info.plist` 文件中添加了必要的键值对,包括但不限于: - `CFBundleURLTypes`: 定义应用的 URL Scheme。 - `GoogleSignInClientID`: 设置 Google Sign-In 的客户端 ID。 如果缺少这些配置,可能导致登录失败或回调异常[^3]。 #### 4. 更新 Google Sign-In SDK 如果使用的 Google Sign-In SDK 版本较旧,可能导致方法签名不匹配或功能异常。建议通过 CocoaPods 更新到最新版本: ```bash pod 'GoogleSignIn' pod install ``` 更新后,确保代码中的方法签名与最新版本的 SDK 保持一致[^4]。 #### 5. 处理 iOS 13 及更高版本的兼容性问题 对于 iOS 13 及更高版本,需要在 `SceneDelegate` 中初始化窗口和根视图控制器,否则可能导致登录界面无法正常显示。例如: ```objc self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene*)scene]; self.window.rootViewController = [[UIViewController alloc] init]; [self.window makeKeyAndVisible]; ``` #### 6. 错误处理 如果登录过程中出现错误,可以通过 `NSError` 对象的 `localizedDescription` 属性获取详细信息。常见的错误包括但不限于: - 用户取消登录。 - 网络连接问题。 - 配置错误(如未正确设置客户端 ID)。 以下是一个完整的实现示例: ```objc [GIDSignIn.sharedInstance signInWithPresentingViewController:self completion:^(GIDSignInResult * _Nullable result, NSError * _Nullable error) { if (error == nil && result != nil) { GIDGoogleUser *user = result.user; NSString *googleIdToken = user.idToken; NSString *googleAccessToken = user.accessToken; NSLog(@"Google ID Token: %@", googleIdToken); NSLog(@"Google Access Token: %@", googleAccessToken); } else { NSLog(@"Google 登录失败:%@", error.localizedDescription); } }]; ``` #### 7. UIViewController 类型的相关用法 `UIViewController` 是 iOS 开发中用于管理用户界面的核心类。以下是一些常见用法: - **初始化视图控制器**:可以通过 `init` 或 `initWithNibName:bundle:` 方法创建视图控制器实例。 - **加载视图**:当视图控制器的视图首次被访问时,会自动调用 `loadView` 和 `viewDidLoad` 方法。 - **生命周期方法**:常用的生命周期方法包括 `viewWillAppear:`、`viewDidAppear:`、`viewWillDisappear:` 和 `viewDidDisappear:`。 - **导航**:可以通过 `UINavigationController` 实现视图控制器的推送和弹出操作。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hiwb

您的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值