两者都实现了类,将使用两者之一。哪个是未定义的

Posted

技术标签:

【中文标题】两者都实现了类,将使用两者之一。哪个是未定义的【英文标题】:Class is implemented in both, One of the two will be used. Which one is undefined 【发布时间】:2017-10-25 12:22:14 【问题描述】:

我对 Cocoapods 中包含的依赖项有疑问。

我有一个框架项目(MyFramework 目标),它也有应用程序目标(MyFrameworkExampleApp)。当我尝试运行该应用程序时,我得到一个充满如下错误的控制台:

类 PodsDummy_AFNetworking 在 /private/var/containers/Bundle/Application/AD85D7EC-2652-4019-94FB-C799D0FBA69B/MyFrameworkExampleApp.app/Frameworks/MyFramework.framework/MyFramework (0x1019a0438) 和 /var/containers/ 中实现捆绑包/应用程序/AD85D7EC-2652-4019-94FB-C799D0FBA69B/MyFrameworkExampleApp.app/MyFrameworkExampleApp (0x10107c558)。将使用两者之一。哪一个是未定义的。

问题是,错误来自仅包含在 MyFramework 目标中的库

这是我的 podfile 的内容:

# Specify platform.
platform :ios, '9.0'

# Let's ignore all warnings from all pods
inhibit_all_warnings!

target 'MyFramework’ do

    # ReactiveCocoa for easier binding between UI and data models.
    pod 'ReactiveCocoa', '< 3.0'

    # ReactiveViewModel for easier handling of active/inactive view models.
    pod 'ReactiveViewModel', '0.3'

    # An Objective-C extension with some nice helpers including @weakify/@strongify.
    pod 'libextobjc', '~> 0.4.1'

    # AFNetworking Security stuff
    pod 'AFNetworking/Security', '~> 2.5.4'

    # KZPropertyMapper to easily map JSON dicts to properties
    pod "KZPropertyMapper"

    # Simple wrapper for KeyChain
    pod 'UICKeyChainStore', '~> 2.0.6'

    # Animated gifs
    pod 'FLAnimatedImage', '~> 1.0'

    # Firebase push notifications
    pod 'Firebase/Core'
    pod 'Firebase/Messaging'

    # Easy image downloading with cache.
    pod 'SDWebImage', '~> 3.7.2'

    # Activity indicator for RBSlider
    pod 'DGActivityIndicatorView'

end

target 'MyFrameworkExampleApp' do

    # Progress indicator
    pod 'MBProgressHUD', '~> 1.0.0'

    # Color picker
    pod 'iOS-Color-Picker'

    # Hockey SDK
    pod 'HockeySDK', '~> 5.0.0'

end

如您所见,App 目标没有继承任何 pod,我也没有任何全局 pod。这可能是什么原因?

【问题讨论】:

【参考方案1】:

我不知道原因,但是如果您打开 cocoapods 创建的应用的 Pods-[AppName].debug.xcconfig 文件,您会发现 OTHER_LDFLAGS 并且您会看到它链接到您在您的应用程序中链接的相同框架框架。因此,如果您删除 -framework [Duplicated framework],警告就会消失。

似乎是 cocoapods 错误

【讨论】:

所以如果你删除 -framework [Duplicated framework] 警告就会消失。 - 这是一个警告,但它实际上会在运行时产生崩溃,例如在使用 ReactiveCocoa 时跨度> 这太疯狂了。这意味着静态/类变量在运行时在框架边界之外不是静态的——这可能会破坏状态并创建各种未定义的行为(例如 Google Maps SDK 以这种方式失败)。解决方法是什么? 这通常不是 CocoaPods 的问题。 这对我有用,但每次你 pod install 时它都会重置 我没有使用 pod。怎么办?【参考方案2】:

我还发现了另一个自动修复错误的脚本。就像我上面回答的一样。 将其添加到您的 Podfile:

post_install do |installer|
    sharedLibrary = installer.aggregate_targets.find  |aggregate_target| aggregate_target.name == 'Pods-[MY_FRAMEWORK_TARGET]' 
    installer.aggregate_targets.each do |aggregate_target|
        if aggregate_target.name == 'Pods-[MY_APP_TARGET]'
            aggregate_target.xcconfigs.each do |config_name, config_file|
                sharedLibraryPodTargets = sharedLibrary.pod_targets
                aggregate_target.pod_targets.select  |pod_target| sharedLibraryPodTargets.include?(pod_target) .each do |pod_target|
                    pod_target.specs.each do |spec|
                        frameworkPaths = unless spec.attributes_hash['ios'].nil? then spec.attributes_hash['ios']['vendored_frameworks'] else spec.attributes_hash['vendored_frameworks'] end || Set.new
                        frameworkNames = Array(frameworkPaths).map(&:to_s).map do |filename|
                            extension = File.extname filename
                            File.basename filename, extension
                        end
                    end
                    frameworkNames.each do |name|
                        if name != '[DUPLICATED_FRAMEWORK_1]' && name != '[DUPLICATED_FRAMEWORK_2]'
                            raise("Script is trying to remove unwanted flags: #name. Check it out!")
                        end
                        puts "Removing #name from OTHER_LDFLAGS"
                        config_file.frameworks.delete(name)
                    end
                end
            end
            xcconfig_path = aggregate_target.xcconfig_path(config_name)
            config_file.save_as(xcconfig_path)
        end
    end
end

【讨论】:

你能看看github.com/CocoaPods/CocoaPods/issues/…,告诉我我做错了什么吗?【参考方案3】:

https://github.com/CocoaPods/CocoaPods/issues/7126#issuecomment-399395611

post_install do |installer|
    applicationTargets = [
        'Pods-SampleApp',
    ]
    libraryTargets = [
        'Pods-SampleLib',
    ]

    embedded_targets = installer.aggregate_targets.select  |aggregate_target|
        libraryTargets.include? aggregate_target.name
    
    embedded_pod_targets = embedded_targets.flat_map  |embedded_target| embedded_target.pod_targets 
    host_targets = installer.aggregate_targets.select  |aggregate_target|
        applicationTargets.include? aggregate_target.name
    

    # We only want to remove pods from Application targets, not libraries
    host_targets.each do |host_target|
        host_target.xcconfigs.each do |config_name, config_file|
            host_target.pod_targets.each do |pod_target|
                if embedded_pod_targets.include? pod_target
                    pod_target.specs.each do |spec|
                        if spec.attributes_hash['ios'] != nil
                            frameworkPaths = spec.attributes_hash['ios']['vendored_frameworks']
                            else
                            frameworkPaths = spec.attributes_hash['vendored_frameworks']
                        end
                        if frameworkPaths != nil
                            frameworkNames = Array(frameworkPaths).map(&:to_s).map do |filename|
                                extension = File.extname filename
                                File.basename filename, extension
                            end
                            frameworkNames.each do |name|
                                puts "Removing #name from OTHER_LDFLAGS of target #host_target.name"
                                config_file.frameworks.delete(name)
                            end
                        end
                    end
                end
            end
            xcconfig_path = host_target.xcconfig_path(config_name)
            config_file.save_as(xcconfig_path)
        end
    end
end

【讨论】:

【参考方案4】:

更新: 我为我的解决方案写了一篇博客文章:https://medium.com/@GalvinLi/tinysolution-fix-cocoapods-duplicate-implement-warning-5a2e1a505ea8

还有一个演示项目: https://github.com/bestwnh/TinySolution


我从互联网上得到了解决方案的想法,但找不到一个解决方案,所以我自己做了一个解决方法。也许代码有点长,但它工作。希望它可以帮助某人。

auto_process_target(,,) 是关键功能,只需将其更改为适合您的项目即可,一切正常。 (因为我用一个framework做multi app target,所以我把app target参数设为一个数组。)

post_install do |installer|

  # you should change the sample auto_process_target method call to fit your project

  # sample for the question
  auto_process_target(['MyFrameworkExampleApp'], 'MyFramework', installer)
  # sample for the multi app use on same framework
  auto_process_target(['exampleiOSApp', 'exampleMacApp'], 'exampleFramework', installer)

end

# the below code no need to modify

def auto_process_target(app_target_names, embedded_target_name, installer)
  words = find_words_at_embedded_target('Pods-' + embedded_target_name,
                                        installer)
  handle_app_targets(app_target_names.map |str| 'Pods-' + str ,
                     words,
                     installer)
end

def find_line_with_start(str, start)
  str.each_line do |line|
      if line.start_with?(start)
        return line
      end
  end
  return nil
end

def remove_words(str, words)
  new_str = str
  words.each do |word| 
    new_str = new_str.sub(word, '')
  end
  return new_str
end

def find_words_at_embedded_target(target_name, installer)
  target = installer.pods_project.targets.find  |target| target.name == target_name 
  target.build_configurations.each do |config|
    xcconfig_path = config.base_configuration_reference.real_path
    xcconfig = File.read(xcconfig_path)
    old_line = find_line_with_start(xcconfig, "OTHER_LDFLAGS")

    if old_line == nil 
      next
    end
    words = old_line.split(' ').select |str| str.start_with?("-l") .map |str| ' ' + str 
    return words
  end
end

def handle_app_targets(names, words, installer)
  installer.pods_project.targets.each do |target|
    if names.index(target.name) == nil
      next
    end
    puts "Updating #target.name OTHER_LDFLAGS"
    target.build_configurations.each do |config|
      xcconfig_path = config.base_configuration_reference.real_path
      xcconfig = File.read(xcconfig_path)
      old_line = find_line_with_start(xcconfig, "OTHER_LDFLAGS")

      if old_line == nil 
        next
      end
      new_line = remove_words(old_line, words)

      new_xcconfig = xcconfig.sub(old_line, new_line)
      File.open(xcconfig_path, "w")  |file| file << new_xcconfig 
    end
  end
end

如果一切正常。当您 pod installpod update 时,您将看到 Update xxxx OTHER_LDFLAGS。然后警告消失了。

【讨论】:

该博客链接与该主题无关。 @ClayBridges 非常感谢您通知我。这是一个很大的错误。我更新了正确的链接。 @Galvin 请在github.com/CocoaPods/CocoaPods/issues/…查看我的新回复 @Galvin 嘿 Galvin,你能看看这个问题吗?我真的在努力解决这个问题...***.com/questions/65024153/…【参考方案5】:

我遇到了同样的问题,在我的例子中,我只是将 "use_frameworks!" 定义为全局解决了这个问题。

Podfile 更改后,您应该这样做,

    清理项目 从 xcode 中退出 删除派生数据 Pod 安装

与下面我的类似 Podfile,

workspace 'sample'
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
platform :ios, '13.0'

def sample_pods
  pod 'Alamofire' , '~> 5.1.0'
  pod 'RxSwift'
  pod 'CodableAlamofire'
end

def sample_framework_pods
  pod 'Alamofire' , '~> 5.1.0'
  pod 'RxSwift'
  pod 'CodableAlamofire'
end

target 'sample' do
  # Pods for sample
    sample_pods
end

target 'sample_framework' do
  project 'sample_framework/sample_framework.xcodeproj'
  # Pods for sample_framework
  sample_framework_pods
end

【讨论】:

不幸的是我没用。【参考方案6】:

我发现的大多数解决方案仅在选定的两个目标之间或主要目标与其他目标之间存在共享依赖关系时才能解决问题。但是,我们有一个复杂得多的项目,其中包含多个目标,其中任何两个目标之间都可能出现重复的框架。

基于TadeasKriz's code,我设法实现了一个解决方案,可以检查所有目标之间以及彼此之间的重复。

def remove_duplicated_frameworks(app_pod_name, installer)
    test_targets = get_test_targets(app_pod_name, installer)
    puts "Detected test targets: #test_targets"

    puts "Removing duplicated frameworks from OTHER_LDFLAGS"
    targets = installer.aggregate_targets.select  |x| !test_targets.include?(x.name) 

    # Checks each pair of targets if they have common pods. Duplicates are removed from the first one's xcconfig.
    for i in 0..targets.size-1 do
        target = targets[i]
        remainingAppPodTargets = targets[i+1..targets.size-1].flat_map(&:pod_targets)

        target.xcconfigs.each do |config_name, config_file|
            # Removes all frameworks which exist in other pods
            remainingAppPodTargets
                .flat_map  |pod_target| get_framework_names(pod_target) 
                .each  |framework| config_file.frameworks.delete(framework) 

            # Saves updated xcconfig
            xcconfig_path = target.xcconfig_path(config_name)
            config_file.save_as(xcconfig_path)
        end
    end
end

def get_test_targets(app_pod_name, installer)
    main_target_name = app_pod_name.gsub("Pods-", "")

    installer.aggregate_targets
        .find  |x| x.name == app_pod_name 
        .user_project
        .targets
        .select  |x| x.test_target_type? 
        .flat_map  |x| ["Pods-#x", "Pods-#main_target_name-#x"] 
        .select  |x| installer.aggregate_targets.map(&:name).include?(x) 
        .uniq
end

def get_framework_names(pod_target)
    frameworkNames = pod_target.specs.flat_map do |spec|
        # We should take framework names from 'vendored_frameworks'.
        # If it's not defined, we use 'spec.name' instead.
        #
        # spec.name can be defined like Framework/Something - we take the first part
        # because that's what appears in OTHER_LDFLAGS.
        frameworkPaths = unless spec.attributes_hash['ios'].nil?
            then spec.attributes_hash['ios']['vendored_frameworks']
            else spec.attributes_hash['vendored_frameworks']
            end || [spec.name.split(/\//, 2).first]

        map_paths_to_filenames(frameworkPaths)
    end

    frameworkNames.uniq
end

def map_paths_to_filenames(paths)
    Array(paths).map(&:to_s).map do |filename|
        extension = File.extname filename
        File.basename filename, extension
    end
end

用法(把这个放在Podfile的末尾):

post_install do |installer|
    remove_duplicated_frameworks('Pods-YourMainTargetName', installer)
end

您还可以将整个解决方案另存为单独的文件,例如 DuplicatedFrameworksRemover.rb 并将其包含在您的 Podfile 中,使用:

load 'DuplicatedFrameworksRemover.rb'

【讨论】:

那么做完之后,你用什么pod命令呢?删除 Pods 文件夹并执行“pod install”? @justdan0227 是的,只是pod install【参考方案7】:

我不知道为什么Xcode会出现这个问题,但就我而言,在我的项目目录中查找库并直接复制其名称并将其粘贴到 Bridging-Header 文件中解决了我的问题并且它有效。

【讨论】:

【参考方案8】:

我不知道实际问题是什么,但是在将应用程序安装在不同的模拟器上之后。为我工作:)。

【讨论】:

以上是关于两者都实现了类,将使用两者之一。哪个是未定义的的主要内容,如果未能解决你的问题,请参考以下文章

两者都实现了 JavaLaunchHelper 类。将使用两者之一。哪一个是未定义的[重复]

Swift UITest - 将使用两者之一。哪个是未定义的

将使用两者之一。哪一个是未定义的。从表视图导航到 Web 视图

ABC 类在 Py2app 应用程序和系统库中都实现了。将使用两者之一

在 SVG 和画布之间,哪个更适合操作/动画多个图像?也许两者都没有,只使用 css3 转换?

我应该使用 Any() 还是 Count() ?哪个更快?如果 IEnumerable 对象中存在任何数据,两者都会返回相同的输出(真或假)吗? [复制]