IOS技术分享| IOS快对讲调度场景实现

news2024/9/20 19:37:22

前言

“快对讲” 是基于 anyRTC 音视频技术 对讲业务的产品,为客户提供专业对讲、多媒体对讲和可视化调度功能。 主要功能包含:

  • 频道与会话
  • 多频道对讲、监听、锁定、强拆
  • 音视频单人、多人呼叫、呼叫调度台
  • 图片、视频上报
  • 视频回传、监看
  • 位置回传
  • 即时消息:文字消息、语音消息、图片消息、视频消息、文件消息、位置消息
  • 文字广播、媒体广播
  • 监控、录像服务、调度台。

功能体验

  • 快对讲官网
  • 快对讲移动端下载
  • 快对讲调度管理平台

快对讲调度管理平台

场景功能实现

一、对讲

效果预览

ARUICalling_talk

部分代码实现
/**
 anyRTC 云平台对讲 频道方法。
 */
__attribute__((visibility("default"))) @interface ARTalkChannel: NSObject


/// ARTalkChannelDelegate 接口类向 App 发送回调通知,上报运行时的频道相关事件。
@property (nonatomic, weak, nullable) id<ARTalkChannelDelegate> channelDelegate;

/// 加入频道。
/// - Parameter completionBlock 同一用户只能同时加入最多 20 个频道。加入频道超限时用户会收到错误码 ARTalkJoinChannelErrorExceedLimit
- (void)joinWithCompletion:(ARTalkJoinChannelBlock _Nullable)completionBlock;

/// 离开频道。
/// - Parameter completionBlock ARTalkLeaveChannelBlock 回调返回本方法的调用结果。
- (void)leaveWithCompletion:(ARTalkLeaveChannelBlock _Nullable)completionBlock;

/// 设置自己的对讲等级
/// - Parameter level 说话等级,0为最大,level 越大等级越低
- (int)setLevel:(int)level;

/// 获取自己的对讲等级
/// - returns 对讲等级
- (int)getLevel;

/// 设置推送音频质量
/// - Parameter nQuality: 1-5 低,中,高,超高,HD,默认为1
- (int)setPushAudioQuality:(int)nQuality;

/// 设置拉取音频质量,暂不可使用
/// - Parameter nQuality: 1-5 低,中,高,超高,HD,默认为1
- (int)setPullAudioQuality:(int)nQuality;

/// 开始对讲
/// - Parameter nTalkOnTime: 对讲时长,0为无限制
/// - returns 0方法调用成功,小于0方法调用失败
- (int)pushToTalk:(int)nTalkOnTime;

/// 结束对讲
/// - returns 0方法调用成功,小于0方法调用失败
- (int)stopPushToTalk;

/// 是否接收频道其它声音
/// - Parameter mute: mute true 静音,false 解除静音
/// - returns 0方法调用成功,小于0方法调用失败
- (int)muteAllRemoteAudio:(BOOL)mute;

/// 打断对讲
/// - returns 0方法调用成功,小于0方法调用失败
- (int)breakTalk;

/// 是否接收广播流
/// - Parameter enable: YES 接收,NO 不接收
- (int)enableAudioStream:(BOOL)enable;

/// 获取频道 ID
- (NSString *)getChannelId;

@end

二、频道与会话

效果预览

ARUICalling_main

部分代码实现
class ARMainViewCellData: ARUICommonCellData {
    /// 群id
    var groupId: String = ""
    /// 是否监听
    var isMonitor: Bool = false
    /// 监听状态
    var monitorStatus: Bool = false
    var groupName: String = ""
    /// 群组类型(0:群组(频道),1:临时群组(会话))
    var groupType: Int = 1
    /// 在线人数
    var onlineCount: NSInteger = 0
    /// 群人数
    var memberCount: NSInteger = 0
    /// 用户在群组内权限(默认0,0:高,1:中,2:低,3:仅听)
    var permission: NSInteger = 0
    var isOwner: Bool = false
    var item: ARCahnnelItem!
    /// 对讲状态(优先级高)
    var talkStatus: String?
    /// 广播状态(优先级低)
    var broadCastStatus: String?
    /// 群组最大发言时长(单位:秒),默认:60s,0表示无限制
    var groupMaxSpeak: NSInteger = 60
    /// 最大排队人数(默认0:无排队,1:5人,2:10人)
    var groupMaxQueue: NSInteger = 0
    var groupDesc: String = ""
    /// 群组级别(默认:0,0:低,1:中,2:高)
    var groupGrade: NSInteger = 0
    var groupImId: NSInteger = 0
    /// 对讲状态
    var userDataNofi: ARTalkUserDataNofi?
    /// 未读数
    var unReadNum: NSInteger = 0
    
    weak var delegate: ARMainViewCellDataDelegate?
    weak var dataSource: ARMainViewCellDataSource?
    
    class func getCellData(item: ARCahnnelItem) -> ARMainViewCellData {
        let cellData = ARMainViewCellData()
        cellData.groupId = item.groupId
        cellData.groupImId = item.groupImId
        cellData.isMonitor = (item.isMonitor == 1)
        cellData.groupName = item.groupName
        cellData.groupType = item.groupType
        cellData.onlineCount = item.onlineCount
        cellData.memberCount = item.memberCount
        cellData.permission = item.permission
        cellData.isOwner = (item.ownerId == localUserData.uId)
        cellData.groupMaxSpeak = item.groupMaxSpeak
        cellData.groupMaxQueue = item.groupMaxQueue
        cellData.groupDesc = item.groupDesc
        cellData.groupGrade = item.groupGrade
        cellData.item = item
        cellData.unReadNum = ARIMMessage.queryGroupUnRead(recvId: UInt64(cellData.groupImId))
        return cellData
    }
    
    func updateMonitorStatus(monitor: Bool, result: @escaping (_ code: NSInteger) -> Void) {
        /// 修改监听状态
        /// 频道: api 接口 + sdk    会话: sdk
        debugPrint("ARUITalking - updateMonitorStatus monitor = \(monitor) monitorStatus = \(monitorStatus)")
        
        guard monitor != monitorStatus else { return }
        
        if groupType == 0 {
            /// api 接口
            ARNetWorkManager.shared.updateGroupMonitorStatus(groupId: groupId, isMonitor: monitor ? 1 : 0) {
                print("ARUITalking - updateGroupMonitorStatus api sucess")
            } failed: { _ in
                print("ARUITalking - updateGroupMonitorStatus api failed")
            }
        }
        
        if !monitor && groupId == ARTalkManager.shared.lockCellData?.groupId {
            /// 解除频道锁定
            ARTalkManager.shared.lockChannel(data: nil)
        }
        
        if ARTalkManager.shared.lockCellData != nil && ARTalkManager.shared.lockCellData?.groupId != groupId && monitor {
            ARTalkManager.shared.getTalkChannel(channelId: groupId).muteAllRemoteAudio(true)
        }
        
        /// sdk 接口
        ARTalkManager.shared.monitorChannel(channelId: groupId, grpImId: groupImId, isMonitor: monitor) { [weak self] code in
            debugPrint("ARUITalking - updateMonitorStatus sdk result = \(code)")
            
            guard let self = self else { return }
            if code == 0 {
                self.item.isMonitor = monitor ? 1 : 0
                self.isMonitor = monitor
                self.monitorStatus = monitor
                if self.delegate != nil {
                    self.delegate?.onMonitorStatusChange()
                }
            }
            result(code)
        }
    }
}

三、音视频通话

效果预览

ARUICalling_call

部分代码实现
@interface ARUICalling : NSObject

/// 基础配置
@property(nonatomic, strong) ARUIConfiguration *config;

+ (instancetype)shareInstance;

/// 通话接口
/// @param users 用户信息
/// @param type 呼叫类型:视频/语音
- (void)call:(NSArray<ARCallUser *> *)users type:(ARUICallingType)type NS_SWIFT_NAME(call(users:type:));

/// 通话接口(用于自定义chanId或添加token)
/// @param users 用户信息
/// @param type 呼叫类型:视频/语音
/// @param chanId 频道id
/// @param token rtc token 动态密钥 【1】安全要求不高: 将值设为 nil 【2】安全要求高: 将值设置为 Token。如果你已经启用了 App Certificate,请务必使用 Token。【3】请务必确保用于生成 Token 的 App ID 和 ARUILogin initWithSdkAppID 时用的是同一个 App ID。
- (void)call:(NSArray<ARCallUser *> *)users type:(ARUICallingType)type chanId:(NSString *_Nullable)chanId token:(NSString *_Nullable)token NS_SWIFT_NAME(call(users:type:chanId:token:));

/// 通话回调
/// @param listener 回调
- (void)setCallingListener:(id<ARUICallingListerner>)listener NS_SWIFT_NAME(setCallingListener(listener:));

/// 设置铃声,建议在30s以内,只支持本地音频文件
/// @param filePath 音频文件路径
- (void)setCallingBell:(NSString *)filePath NS_SWIFT_NAME(setCallingBell(filePath:));

/// 开启静音模式(默认关)
- (void)enableMuteMode:(BOOL)enable NS_SWIFT_NAME(enableMuteMode(enable:));

/// 打开悬浮窗(默认关)
- (void)enableFloatWindow:(BOOL)enable NS_SWIFT_NAME(enableFloatWindow(enable:));

/// 开启自定义路由(默认关)
/// @param enable 打开后,在onStart回调中,会收到对应的ViewController对象,可以自行决定视图展示方式
- (void)enableCustomViewRoute:(BOOL)enable NS_SWIFT_NAME(enableCustomViewRoute(enable:));

/// rtc token 鉴权 (收到onCallInvitedByToken回调时调用)
/// @param token 安全机制
- (void)updateCallingToken:(NSString *_Nonnull)token NS_SWIFT_NAME(updateCallingToken(token:));

@end

四、视频回传、监看

效果预览

ARUICalling_monitor

部分代码实现
    func initializeEngine() {
        // init ARtcEngineKit
        rtcEngine = ARtcEngineKit.sharedEngine(withAppId: ARUILogin.getSdkAppID(), delegate: self)
        let rtcConfig = ARCoreConfig.default().rtcConfig
        if (rtcConfig?.addr.count != 0 && rtcConfig?.port != 0) {
            /// 配置私有云
            let dic: NSDictionary = ["Cmd": "ConfPriCloudAddr", "ServerAdd": rtcConfig?.addr as Any, "Port": rtcConfig?.port as Any] as NSDictionary
            rtcEngine.setParameters(toJSONString(dict: dic))
        }
        
        rtcEngine.setChannelProfile(.liveBroadcasting)
        rtcEngine.enableAudioVolumeIndication(2000, smooth: 3, report_vad: true)
        rtcEngine.setClientRole(.broadcaster)
        
        let configuration = ARCameraCapturerConfiguration()
        configuration.cameraDirection = .rear
        rtcEngine.setCameraCapturerConfiguration(configuration)
        
        rtcEngine.enableVideo()
        let fpsValue = ARUIVideoFrameRateFps(rawValue: localConfig.videoFps)?.fps()
        rtcEngine.setVideoEncoderConfiguration(ARVideoEncoderConfiguration(size: (ARUIVideoDimension(rawValue: localConfig.videoSize)?.dimension())!, frameRate: ARVideoFrameRate(rawValue: fpsValue ?? 15)!, bitrate: 500, orientationMode: .adaptative))
        setLocalVideoRender(render: view)
    }
    
    func setLocalVideoRender(render: UIView) {
        let videoCanvas = ARtcVideoCanvas()
        videoCanvas.view = render
        videoCanvas.renderMode = .hidden
        rtcEngine.setupLocalVideo(videoCanvas)
        rtcEngine.startPreview()
    }
    
    func joinChannel(token: String?, expire: Bool) {
        rtcEngine.joinChannel(byToken: token, channelId: channelId, uid: userInfo.uId) { [weak self] channel, uid, elapsed in
            guard let self = self else { return }
            if !expire {
                self.startTimer()
                self.startReport()
            }
            debugPrint("ARUIPassBack - joinChannel sucess")
        }
    }

五、图片、视频上报

ARUICalling_report

部分代码实现
@objc protocol ARReportUploadManagerDelegate: NSObjectProtocol {
    /// 上报进度
    @objc optional func onReportDataProgress(progress: CGFloat, identification: String)
    /// 上报成功
    @objc optional func onReportDataSucess(identification: String)
    /// 上报失败
    @objc optional func onReportDataFailure(identification: String)
}

    func fetchImage(for asset: PHAsset) {
        let option = PHImageRequestOptions()
        option.resizeMode = .fast
        option.isNetworkAccessAllowed = true
        
        PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: option) { [weak self] image, info in
            var downloadFinished = false
            if let info = info {
                downloadFinished = !(info[PHImageCancelledKey] as? Bool ?? false) && (info[PHImageErrorKey] == nil)
            }
            let isDegraded = (info?[PHImageResultIsDegradedKey] as? Bool ?? false)
            if downloadFinished, !isDegraded {
                guard let self = self else { return }
                self.addNewData(images: [image!], assets: [asset])
            }
        }
    }
    
    func calculateFileSize() {
        var fileSize = 0
        var sandBoxSize = 0
        for detail in reportInfo.detail {
            if detail.type == 2 {
                fileSize = detail.size
                sandBoxSize = detail.compressSize
                break
            } else {
                fileSize += detail.size
                sandBoxSize += detail.compressSize
            }
        }
        
        delegate?.onReportDataSourceChange?(fileSize: "\(formatLength(length: fileSize))", compressSize: "\(formatLength(length: sandBoxSize))", enable: assets.count != 0)
    }

六、位置回传

ARUICalling_location

部分代码实现
extension ARUIShareLocationController: MAMapViewDelegate {
    func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
        /// 大头针、气泡
        if annotation is MAPointAnnotation {
            let customReuseIndetifier: String = "annotationReuseIndetifier"
            var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: customReuseIndetifier) as? ARUICustomAnnotationView
            if annotationView == nil {
                annotationView = ARUICustomAnnotationView(annotation: annotation, reuseIdentifier: customReuseIndetifier)
                annotationView?.image = UIImage(named: "icon_direction")
                // 设置为false,用以调用自定义的calloutView
                annotationView?.canShowCallout = false
                // 设置中心点偏移,使得标注底部中间点成为经纬度对应点
                annotationView?.centerOffset = CGPoint(x: 0, y: -18)
                annotationView?.isDraggable = false
            }
            
            if annotation.isKind(of: ARUIMapAnnotation.self) {
                let mapAnnotation = annotation as! ARUIMapAnnotation
                annotationView?.setHeadUrl(url: mapAnnotation.faceUrl)
                annotationView?.setNickName(text: mapAnnotation.nickName)
            }
            
            if annotation.isKind(of: MAUserLocation.self) {
                localAnnotationView = annotationView
                localAnnotationView?.setHeadUrl(url: localUserData.faceUrl)
                localAnnotationView?.setNickName(text: localUserData.nickName)
                localLocation = annotation as? MAUserLocation
            }
            
            return annotationView
        }
           
        return nil
    }
    
    func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
        if (!updatingLocation && localAnnotationView != nil) {
            UIView.animate(withDuration: 0.1) {
                let degree = userLocation.heading.trueHeading - self.mapView.rotationDegree
                self.localAnnotationView?.imageView.transform = CGAffineTransform(rotationAngle: degree * Double.pi / 180.0)
            }
        }
    }
}

七、即时消息

ARUICalling_im

部分代码实现
/// 消息内容类型
enum ARIMElemType: NSInteger, Codable, HandyJSONEnum {
    /// 未知消息
    case none = 100
    /// 文本消息
    case text = 101
    /// 图片消息
    case picture = 102
    /// 语音消息
    case voice = 103
    /// 视频消息
    case video = 104
    /// ptt 语音
    case pushtotalk = 105
    /// 文件消息
    case file = 106
    case atText = 107
    /// 合并消息
    case merger = 108
    case card = 109
    /// 地理位置消息
    case location = 110
    /// 自定义消息
    case custom = 111
    case revoke = 112
    case hasReadReceipt = 113
    case typing = 114
    case quote = 115
    case common = 200
    case groupMsg = 201
}


/// 消息状态
enum ARIMMessageStatus: NSInteger, Codable, HandyJSONEnum {
    case sending = 1
    case sendSuccess = 2
    case sendFailed = 3
    case hasDeleted = 4
    case revoked = 5
    case filtered = 6
}

/// IM消息
///"sendId":3578970541,"recvId":2723541307,"clientMsgId":"1653488317610","sessionType":1,"contentType":101,"content":"IM消息","curSeq":1011,"sendTime":1653488317,"status":2
struct ARIMMessage: HandyJSON, PersistableRecord {
    /// 序列号
    var curSeq: UInt64!
    /// 消息 Id
    var clientMsgId: String!
    /// 发送者 Id
    var sendId: UInt64!
    /// 接受者 id
    var recvId: UInt64!
    /// 消息类型(点对点消息:1,群组消息:2)
    var sessionType: ARIMSessionType = .c2c
    /// 消息内容类型,附加信息中的<消息内容类型>
    var contentType: ARIMElemType = .none
    /// 消息内容
    var content: String = ""
    /// 消息状态
    var status: ARIMMessageStatus?
    /// 发送时间(单位:毫秒)
    var sendTime: Int?
    /// 发送者平台类型
    var senderPlatformId: ARIMPlatform?
    /// 附加消息
    var ex: String?
    
    var syncMsgId: String = ""
    /// 消息保存时间(单位:秒)
    var createTime: Int = 0
    /// 消息归属Id
    var msgImId: Int = 0
    /// 已读状态,默认未读
    var isRead: Bool = false
    /// 是否播放(针对语音、ptt 已读未读),默认未播放
    var isPlay: Bool = false
    
    /
    //  自定义消息体
    /

    /// 图片消息
    var imageElem: ARUIImageElem?
    /// 视频消息
    var videoElem: ARUIVideoElem?
    /// 语音消息
    var soundElem: ARUISoundElem?
    /// 文件消息
    var fileElem: ARUIFileElem?
    /// 位置消息
    var locationElem: ARUILocationElem?
}

extension ARIMMessage {
    func getImageElem() -> ARUIImageElem {
        /// 获取图片消息单元
        var elem = ARUIImageElem()
        var jsonStr = content.base64Decoded()
        /// 兼容之前未base64的消息
        if content.base64Decoded() == "【不支持的消息类型】" {
            jsonStr = content
        }
        elem.imageList = JSONDeserializer<ARUIImageItem>.deserializeModelArrayFrom(json: jsonStr) as? [ARUIImageItem]
        return elem
    }
    
    func getVideoElem() -> ARUIVideoElem {
        /// 获取视频消息单元
        let elem = JSONDeserializer<ARUIVideoElem>.deserializeFrom(json: content.base64Decoded())
        return elem!
    }
    
    func getSoundElem() -> ARUISoundElem {
        /// 获取音频消息单元
        let elem = JSONDeserializer<ARUISoundElem>.deserializeFrom(json: content.base64Decoded())
        return elem!
    }
    
    func getFileElem() -> ARUIFileElem {
        /// 获取文件消息单元
        let elem = JSONDeserializer<ARUIFileElem>.deserializeFrom(json: content.base64Decoded())
        return elem!
    }
    
    func getLocationElem() -> ARUILocationElem {
        /// 获取位置消息单元
        let elem = JSONDeserializer<ARUILocationElem>.deserializeFrom(json: content.base64Decoded())
        return elem!
    }
}

八、文字广播、媒体广播

ARUICalling_broadcast

部分代码实现
@protocol ARTalkChannelDelegate <NSObject>
@optional

/// 广播开启
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param uid 用户id
/// @param userData 自定义信息
- (void)channel:(ARTalkChannel * _Nonnull)channel userStreamOn:(NSString *)uid userData: (NSString * _Nullable)userData;

/// 广播关闭
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param uid 用户id
/// @param userData 自定义信息
- (void)channel:(ARTalkChannel * _Nonnull)channel userStreamOff:(NSString *)uid userData: (NSString * _Nullable)userData;

/// 开始对讲回调
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param code 错误码
- (void)channel:(ARTalkChannel * _Nonnull)channel pushToTalkResult:(ARTalkPushToTalkErrorCode)code;

/// 结束对讲回调
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param code 错误码
- (void)channel:(ARTalkChannel * _Nonnull)channel pushToTalkEnded:(ARTalkPushToTalkEndErrorCode)code;

/// 其他用户开始对讲回调
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param uid 用户id
/// @param userData 自定义信息
/// @param level 用户等级
- (void)channel:(ARTalkChannel * _Nonnull)channel userIsTalkOn:(NSString *)uid userData: (NSString * _Nullable)userData userLevel:(NSInteger)level;

/// 其他用户结束对讲回调
/// @param channel 所在频道。详见 ARTalkChannel 。
/// @param uid 用户id
/// @param userData 自定义信息
- (void)channel:(ARTalkChannel * _Nonnull)channel userIsTalkOff:(NSString *)uid userData: (NSString * _Nullable)userData;

@end

快对讲 iOS 端基础库

platform :ios, '11.0'
use_frameworks!

target 'ARUITalking' do
    # anyRTC 音视频库
    pod 'ARtcKit_iOS', '~> 4.3.0.3'
    # anyRTC 实时消息库
    pod 'ARtmKit_iOS', '~> 1.1.0.1'
    # anyRTC 对讲库
    pod 'ARTalkKit_iOS'
end

以上就是快对讲IOS端的基本功能实现。快对讲调度系统将语音、视频、图像、文本消息等信息高度融合一体,搭建综合指挥调度业务,不仅实现企业通讯数字信息化,进行高效协作提升企业整体形象,也能满足紧急救援、紧急决策等要求,达到统一指挥、联合行动的目的。开发者可以基于 ARUICalling 音视频通话开源组件,来开发自己的专属快对讲调度系统。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/138970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CUDA】C++实现warpaffine仿射变换及其逆变换

目录仿射变换矩阵工具类进行前向仿射变换&#xff1a;i->d进行仿射变换逆向变换d->i仿射变换矩阵工具类 假设有图片i&#xff0c;要将其仿射变换至图片d&#xff0c;使用下面的类计算仿射变换矩阵i2d及d2i&#xff1a; 在调用compute函数后&#xff0c;输入i及d的尺寸&a…

[3] Jenkins 系列:如何获取出发Jenkins Job的用户信息?

Jenkins提供两种方式的Script&#xff0c;一种是基于声明式的&#xff0c;一种是基于脚本式的。 Jenkins申明式的格式 Jenkins脚本式的格式 Jenkins 官方推荐使用申明式的方式定义Jenkins的Pipeline。 有的时候我们需要在Pipeline给开发团队发消息或者邮件&#xff0c;告知当…

MAC(m1)-VMWare Fusion安装CentOS7.9

下载安装VMWare Fusion&#xff0c;安装完成后打开 https://blog.csdn.net/ZHOU_VIP/article/details/128513824 centos7.9安装镜像拖过来&#xff1a; 打开自定义设置&#xff1a; 换文件夹&#xff1a; 问题出来了&#xff0c;点击install闪一下&#xff0c;就没了&#xff…

C进阶:结构体的内存对齐

目录 本篇文章注意讲解结构体的内存对齐。 &#x1f54a;️&#x1f432;一.为什么存在内存对齐 &#x1f916;&#x1f47b;二.内存对齐规则 &#x1f42c;&#x1f431;三.实例 &#x1f407;例1. &#x1f984; 例2. &#x1f42f;例3. &#x1f63c;例4. 一.为什么…

二十四节气-小寒。文案、海报分享,小寒料峭 年味渐浓。

小寒&#xff0c;是二十四节气中的第23个节气&#xff0c;冬季的第5个节气&#xff0c;正处在“二九”“三九”期间&#xff0c;可以说是一年中最冷的时段。 中国古代将“小寒”分为三候&#xff1a;“一候雁北乡&#xff0c;二候鹊始巢&#xff0c;三候雉始鸲。” 大雁开始向…

Java堆空间(Heap Space)

Java 堆空间(Heap Space)概述在Java程序中&#xff0c;堆是JVM内存空间中最大的一块&#xff0c;同时我们知道&#xff0c;每个线程都拥有一个虚拟机栈&#xff0c;但是堆不同&#xff0c;Java堆是被所有线程共享的一块内存区域&#xff0c;在虚拟机启动时创建。在《Java虚拟机…

STM32——TIM输入捕获

文章目录一、TIM输入捕获输入捕获简介频率测量二、通用定时器的输入捕获通道通用定时器框图通道的输出部分三、主从触发模式主模式从模式四、输入捕获基本结构五、PWMI基本结构六、输入捕获模式测频率电路设计关键代码七、PWMI模式测频率占空比电路设计关键代码八、定时器库函数…

分而治之——图的连通性问题及板子

连通性的判断 两大算法&#xff1a;并查集 和 图的遍历&#xff08;DFS BFS&#xff09; 分而治之的题目与解答 在这道题的下面 3587. 连通图 - AcWing题库 连通性的判断 两种方法 1.这里连通性的判断是判断连通分支是否包含所有的点。 2.也可以不开cnt数组&#xff0c;直接…

【算法】贪心算法(第四章习题解答)

4 贪心算法 4.1 若在 0−10-10−1 背包问题中, 各物品依重量递增排列时, 其价值恰好依递减序排列. 对于这个特殊的 0−10-10−1 背包问题, 设计一个有效算法找出最优解, 并说明算法的正确性. 算法设计&#xff1a;由题目所给的信息可以知道这种特殊的背包问题可以通过贪心算法…

基于多保真方法来估计方差和全局敏感度指数分析(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 此代码实现了多保真方法来估计方差和全局敏感度指数。当模型具有不确定的输入时&#xff0c;模型输出也是不确定的。基于方差的…

C++与QML混合编程

一、前言 简单来说&#xff0c;混合编程就是通过Qml高效便捷的构建UI界面&#xff0c;而使用C 来实现业务逻辑和复杂算法。Qt集成了QML引擎和Qt元对象系统&#xff0c;使得QML很容易从C 中得到扩展&#xff0c;在一定的条件下&#xff0c;QML就可以访问QObject派生类的成员&am…

112.(leaflet之家)leaflet椭圆修改

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

OpenHarmony之轻量系统编译构建流程

首先我们先来熟悉几个概念&#xff1a; - 子系统 子系统是一个逻辑概念&#xff0c;它由一个或多个具体的组件组成。OpenHarmony整体遵从分层设计&#xff0c;从下向上依次为&#xff1a;内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级…

别人家的公司年终奖52个月工资-互联网企业年终裁员脸在哪

52个月工资&#xff0c;开玩笑吧&#xff0c;还真不是。据台湾媒体报道&#xff0c;中国台湾长荣海运年终奖出炉&#xff0c;继去年40个月年终奖后&#xff0c;今年再创新高&#xff0c;传言最高发放52个月年终奖金。以基层员工月薪5万新台币计算&#xff0c;表现好的员工可领到…

6.vector、set和map

一、vector 1.简介 有些时候想开一个数组&#xff0c;但是却不知道应该开多大长度的数组合适&#xff0c;因为我们需要用到的数组可能会根据情况变动。这时候我们就需要用到动态数组。 所谓动态数组&#xff0c;也就是不定长数组&#xff0c;数组的长度是可以根据我们的需要…

第四章快速排序——分而治之

分而治之&#xff08;divide and conquer,D&C&#xff09; D&C算法是递归的&#xff0c;并且有2个步骤&#xff1a; 找出基线条件&#xff0c;并且条件尽可能简单不断将问题分解&#xff0c;直到符合基线条件 给定一个数组&#xff0c;求和&#xff1a; 利用循环很容…

秒懂双向链表

目录 一、双向链表概述 二、模拟实现双向链表 1、头插法插入元素 2、尾插法插入元素 3、在指定位置插入元素 4、查询双向链表中是否包含key 5、删除第一次出现关键字为key的结点 6、删除所有值为key的结点 7、求双向链表的长度 8、遍历双向链表 9、清空双向链表 三…

【 uniapp - 黑马优购 | 商品列表 】如何实现数据获取、结构渲染、自定义组件的封装

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

在 Mac 上将 PDF 转换为 Word 的 5 种简单方法

当谈到将PDF格式转换为Word格式时&#xff0c;用户可能会从互联网上搜索并尝试在线将PDF转换为Word。如果是这样&#xff0c;您可能会得到不好的结果并冒着文件本身的风险。在线 PDF 到 Word 转换器工具可能会产生低质量的输出&#xff0c;对文件大小有限制&#xff0c;更糟糕的…

maven多模块依赖版本不一致问题

项目结构&#xff1a; ├─springcloud-alibaba ├─.idea├─shop-common├─shop-order├─shop-product└─shop-user项目环境&#xff1a; 父工程&#xff1a; <properties><spring-cloud.version>Greenwich.RELEASE</spring-cloud.version><sprin…