枚举副本时“NSCFArray在枚举时发生突变”错误

时间:2012-02-08 17:37:00

标签: python objective-c nsarray enumeration pyobjc

def leopardRemoveWireless(networkName):
  plistPath = '/Library/Preferences/SystemConfiguration/preferences.plist'
  # Sanity checks for the plist
  if os.path.exists(plistPath):
    try:
      pl = NSMutableDictionary.dictionaryWithContentsOfFile_(plistPath)
    except:
      print 'Unable to parse file at path: %s' % plistPath
      sys.exit(1)
  else:
    print 'File does not exist at path: %s' % plistPath
    sys.exit(1)
  # Create a copy of the dictionary due to emuration
  copy = NSDictionary.dictionaryWithDictionary_(pl)
  # Iterate through network sets
  for Set in copy['Sets']:
    UserDefinedName = copy['Sets'][Set]['UserDefinedName']
    print 'Processing location: %s' % UserDefinedName

    for enX in copy['Sets'][Set]['Network']['Interface']:
      print 'Processing interface: %s' % enX
      # I think this will always be a single key but this works either way
      for key in copy['Sets'][Set]['Network']['Interface'][enX]:
        print 'Processing Service: %s' % key
        # Try to grab the PreferredNetworks key if any
        try:
          # Iterate through preferred network sets
          index = 0
          for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:
            SSID_STR = PreferredNetwork['SSID_STR']
            print 'Processing SSID: %s' % SSID_STR
            # If the preferred network matches our removal SSID
            if SSID_STR == networkName:
              print 'Found SSID %s to remove' % SSID_STR
              # Delete our in ram copy
              print 'Processing Set: %s' % Set
              print 'Processing enX: %s' % enX
              print 'Processing key: %s' % key
              del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]
            index += 1
        except KeyError:
           print 'Skipping interface without PreferredNetworks'

我正在编辑一个相当复杂的(字典)plist,然后在找到特定的键值对后将更改写回文件。问题是,即使我正在制作属性列表字典的副本:

copy = NSDictionary.dictionaryWithDictionary_(pl)

当我编辑原始文件时,它给了我标准的“枚举时突变”错误,只是将循环键作为标记(注意缺少引号)。

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

我的语法是否以某种方式导致它尝试编辑pl词典而不是copy?这是输出:

  

...   处理组:D5C0A0F4-613A-4121-B6AE-4CBA6E2635FF   处理enX:en1   处理密钥:AirPort   Traceback(最近一次调用最后一次):     文件“/ Users / tester / Desktop / wifiutil”,第1164行,in       sys.exit(主())     文件“/ Users / tester / Desktop / wifiutil”,第1135行,主要       removeWireless(OSVERSION,网络)     文件“/ Users / tester / Desktop / wifiutil”,第1051行,在removeWireless中       leopardRemoveWireless(网络)
    在leopardRemoveWireless中输入文件“/ Users / tester / Desktop / wifiutil”,第528行       for CopyNetwork in copy ['Sets'] [Set] ['Network'] ['Interface'] [enX] [key] ['PreferredNetworks']:     在enumeratorGenerator中输入文件“/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python/PyObjC/objc/_convenience.py”,第431行       yield container_unwrap(anEnumerator.nextObject(),StopIteration)   objc.error:NSGenericException - * 集合在枚举时发生了变异。

1 个答案:

答案 0 :(得分:1)

我认为问题是字典的嵌套性质。 dictionaryWithDictionary_()没有做类似深层复制的任何事情;它只是创建一个新的NSDictionary并复制值的指针(它确实复制了键本身,因为这是NSDictionary的性质。)

这意味着,虽然您有一个可用于枚举的新顶级,但内部字典和数组与原始字体完全相同。

你的最后一个循环:

for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:

枚举其中一个内部数组,然后尝试使用del语句进行变异:

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

没有复制;它与您在for中使用的数组对象相同,这会导致异常。您可以通过将两个表达式传递给id()来测试它。

您必须要么对原始字典进行全面深度复制,要么(可能更好)在枚举之前获取最后一个级别的副本。