1""" 2This module implements a callback function that is used by the C code to 3add Python special methods to Objective-C classes with a suitable interface. 4 5This module contains no user callable code. 6 7TODO: 8- Add external interface: Framework specific modules may want to add to this. 9 10- These are candidates for implementation: 11 12 >>> from Foundation import * 13 >>> set(dir(list)) - set(dir(NSMutableArray)) 14 set(['__delslice__', '__imul__', '__getslice__', '__setslice__', 15 '__iadd__', '__mul__', '__add__', '__rmul__']) 16 >>> set(dir(dict)) - set(dir(NSMutableDictionary)) 17 set(['__cmp__']) 18 19""" 20from objc._objc import _setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature, _block_call 21from objc._objc import registerMetaDataForSelector 22import sys 23import warnings 24import collections 25 26__all__ = ( 'addConvenienceForSelector', 'addConvenienceForClass' ) 27 28 29_CONVENIENCE_METHODS = {} 30CLASS_METHODS = {} 31 32if sys.version_info[0] == 2: 33 # Use 'xrange' as range to get the same behavior on Python 2 and 3. 34 range = xrange 35 36 37def addConvenienceForSelector(selector, methods): 38 """ 39 Add the list with methods to every class that has a selector with the 40 given name. 41 """ 42 warnings.warn("addConvenienceForSelector is on the way out", DeprecationWarning) 43 _CONVENIENCE_METHODS[selector] = methods 44 45def addConvenienceForClass(classname, methods): 46 """ 47 Add the list with methods to the class with the specified name 48 """ 49 CLASS_METHODS[classname] = methods 50 51NSObject = lookUpClass('NSObject') 52 53def add_convenience_methods(super_class, name, type_dict): 54 """ 55 Add additional methods to the type-dict of subclass 'name' of 56 'super_class'. 57 58 _CONVENIENCE_METHODS is a global variable containing a mapping from 59 an Objective-C selector to a Python method name and implementation. 60 61 CLASS_METHODS is a global variable containing a mapping from 62 class name to a list of Python method names and implementation. 63 64 Matching entries from both mappings are added to the 'type_dict'. 65 """ 66 if type_dict.get('__objc_python_subclass__'): 67 if 'bundleForClass' not in type_dict: 68 cb = currentBundle() 69 def bundleForClass(cls): 70 return cb 71 type_dict['bundleForClass'] = selector(bundleForClass, isClassMethod=True) 72 73 look_at_super = (super_class is not None and super_class.__name__ != 'Object') 74 75 for k, sel in list(type_dict.items()): 76 if not isinstance(sel, selector): 77 continue 78 79 # 80 # Handle some common exceptions to the usual rules: 81 # 82 83 sel = sel.selector 84 85 if sel in _CONVENIENCE_METHODS: 86 v = _CONVENIENCE_METHODS[sel] 87 for nm, value in v: 88 if nm in type_dict and isinstance(type_dict[nm], selector): 89 90 # Clone attributes of already existing version 91 92 t = type_dict[nm] 93 v = selector(value, selector=t.selector, 94 signature=t.signature, isClassMethod=t.isClassMethod) 95 96 type_dict[nm] = v 97 98 elif look_at_super and hasattr(super_class, nm): 99 # Skip, inherit the implementation from a super_class 100 pass 101 102 elif nm not in type_dict: 103 type_dict[nm] = value 104 105 if name in CLASS_METHODS: 106 for nm, value in CLASS_METHODS[name]: 107 type_dict[nm] = value 108 109 110 if name == 'NSObject': 111 class kvc (object): 112 """ 113 Key-Value-Coding accessor for Cocoa objects. 114 115 Both attribute access and dict-like indexing will attempt to 116 access the requested item through Key-Value-Coding. 117 """ 118 __slots__ = ('__object',) 119 def __init__(self, value): 120 self.__object = value 121 122 def __repr__(self): 123 return "<KVC accessor for %r>"%(self.__object,) 124 125 def __getattr__(self, key): 126 try: 127 return self.__object.valueForKey_(key) 128 except KeyError as msg: 129 if hasattr(msg, '_pyobjc_info_') and msg._pyobjc_info_['name'] == 'NSUnknownKeyException': 130 raise AttributeError(key) 131 132 raise 133 def __setattr__(self, key, value): 134 if not key.startswith('_'): 135 return self.__object.setValue_forKey_(value, key) 136 else: 137 super(kvc, self).__setattr__(key, value) 138 139 def __getitem__(self, key): 140 if not isinstance(key, STR_TYPES): 141 raise TypeError("Key must be string") 142 return self.__object.valueForKey_(key) 143 144 def __setitem__(self, key, value): 145 if not isinstance(key, STR_TYPES): 146 raise TypeError("Key must be string") 147 return self.__object.setValue_forKey_(value, key) 148 149 type_dict['_'] = property(kvc) 150 151_setClassExtender(add_convenience_methods) 152 153 154# 155# The following conveniences should strictly speaking be in 156# in pyobjc-framework-Foundation, but as they are very fundamental 157# we're keeping them here. 158# 159 160def __getitem__objectForKey_(self, key): 161 res = self.objectForKey_(container_wrap(key)) 162 return container_unwrap(res, KeyError, key) 163 164def has_key_objectForKey_(self, key): 165 res = self.objectForKey_(container_wrap(key)) 166 return res is not None 167 168def get_objectForKey_(self, key, dflt=None): 169 res = self.objectForKey_(container_wrap(key)) 170 if res is None: 171 res = dflt 172 return res 173 174_CONVENIENCE_METHODS[b'objectForKey:'] = ( 175 ('__getitem__', __getitem__objectForKey_), 176 ('get', get_objectForKey_), 177 ('__contains__', has_key_objectForKey_), 178) 179if sys.version_info[0] == 2: 180 _CONVENIENCE_METHODS[b'objectForKey:'] += ( 181 ('has_key', has_key_objectForKey_), 182 ) 183 184 185 186 187def __delitem__removeObjectForKey_(self, key): 188 self.removeObjectForKey_(container_wrap(key)) 189 190_CONVENIENCE_METHODS[b'removeObjectForKey:'] = ( 191 ('__delitem__', __delitem__removeObjectForKey_), 192) 193 194def update_setObject_forKey_(self, *args, **kwds): 195 # XXX - should this be more flexible? 196 if len(args) == 0: 197 pass 198 elif len(args) != 1: 199 raise TypeError("update expected at most 1 arguments, got {0}".format( 200 len(args))) 201 202 203 else: 204 other = args[0] 205 if hasattr(other, 'keys'): 206 # This mirrors the implementation of dict.update, but seems 207 # wrong for Python3 (with collectons.Dict) 208 for key in other.keys(): 209 self[key] = other[key] 210 211 else: 212 for key, value in other: 213 self[key] = value 214 215 for k in kwds: 216 self[k] = kwds[k] 217 218def setdefault_setObject_forKey_(self, key, dflt=None): 219 try: 220 return self[key] 221 except KeyError: 222 self[key] = dflt 223 return dflt 224 225def __setitem__setObject_forKey_(self, key, value): 226 self.setObject_forKey_(container_wrap(value), container_wrap(key)) 227 228pop_setObject_dflt=object() 229def pop_setObject_forKey_(self, key, dflt=pop_setObject_dflt): 230 try: 231 res = self[key] 232 except KeyError: 233 if dflt == pop_setObject_dflt: 234 raise KeyError(key) 235 res = dflt 236 else: 237 del self[key] 238 return res 239 240NSAutoreleasePool = lookUpClass('NSAutoreleasePool') 241 242def popitem_setObject_forKey_(self): 243 try: 244 it = self.keyEnumerator() 245 k = container_unwrap(it.nextObject(), StopIteration) 246 except (StopIteration, IndexError): 247 raise KeyError("popitem on an empty %s" % (type(self).__name__,)) 248 else: 249 result = (k, container_unwrap(self.objectForKey_(k), KeyError)) 250 self.removeObjectForKey_(k) 251 return result 252 253_CONVENIENCE_METHODS[b'setObject:forKey:'] = ( 254 ('__setitem__', __setitem__setObject_forKey_), 255 ('update', update_setObject_forKey_), 256 ('setdefault', setdefault_setObject_forKey_), 257 ('pop', pop_setObject_forKey_), 258 ('popitem', popitem_setObject_forKey_), 259) 260 261 262_CONVENIENCE_METHODS[b'count'] = ( 263 ('__len__', lambda self: self.count()), 264) 265 266def containsObject_has_key(self, elem): 267 return bool(self.containsObject_(container_wrap(elem))) 268 269_CONVENIENCE_METHODS[b'containsObject:'] = ( 270 ('__contains__', containsObject_has_key), 271) 272 273 274 275def nsobject_hash(self, _max=sys.maxsize, _const=((sys.maxsize + 1) * 2)): 276 rval = self.hash() 277 if rval > _max: 278 rval -= _const 279 # -1 is not a valid hash in Python and hash(x) will 280 # translate a hash of -1 to -2, so we might as well 281 # do it here so that it's not too surprising.. 282 if rval == -1: 283 rval = -2 284 return int(rval) 285 286def nsobject__eq__(self, other): 287 return bool(self.isEqualTo_(other)) 288 289def nsobject__ne__(self, other): 290 return bool(self.isNotEqualTo_(other)) 291 292def nsobject__gt__(self, other): 293 return bool(self.isGreaterThan_(other)) 294 295def nsobject__ge__(self, other): 296 return bool(self.isGreaterThanOrEqualTo_(other)) 297 298def nsobject__lt__(self, other): 299 return bool(self.isLessThan_(other)) 300 301def nsobject__le__(self, other): 302 return bool(self.isLessThanOrEqualTo_(other)) 303 304CLASS_METHODS["NSObject"] = ( 305 ('__hash__', nsobject_hash), 306 ('__eq__', nsobject__eq__), 307 ('__ne__', nsobject__ne__), 308 ('__gt__', nsobject__gt__), 309 ('__ge__', nsobject__ge__), 310 ('__lt__', nsobject__lt__), 311 ('__le__', nsobject__le__), 312) 313 314if sys.version_info[0] == 2: 315 def nsobject__cmp__(self, other): 316 try: 317 func = self.compare_ 318 319 except AttributeError: 320 return NotImplemented 321 if self < other: 322 return -1 323 elif self > other: 324 return 1 325 else: 326 return 0 327 328 else: 329 return func(other) 330 331 CLASS_METHODS["NSObject"] += ( 332 ("__cmp__", nsobject__cmp__), 333 ) 334 335 336 337 338_CONVENIENCE_METHODS[b'length'] = ( 339 ('__len__', lambda self: self.length()), 340) 341 342_CONVENIENCE_METHODS[b'addObject:'] = ( 343 ('append', lambda self, item: self.addObject_(container_wrap(item))), 344) 345 346def reverse_exchangeObjectAtIndex_withObjectAtIndex_(self): 347 begin = 0 348 end = len(self) - 1 349 while begin < end: 350 self.exchangeObjectAtIndex_withObjectAtIndex_(begin, end) 351 begin += 1 352 end -= 1 353 354_CONVENIENCE_METHODS[b'exchangeObjectAtIndex:withObjectAtIndex:'] = ( 355 ('reverse', reverse_exchangeObjectAtIndex_withObjectAtIndex_), 356) 357 358def ensureArray(anArray): 359 if not isinstance(anArray, (NSArray, list, tuple)): 360 anArray = list(anArray) 361 return anArray 362 363 364def extend_addObjectsFromArray_(self, anArray): 365 self.addObjectsFromArray_(ensureArray(anArray)) 366 367_CONVENIENCE_METHODS[b'addObjectsFromArray:'] = ( 368 ('extend', extend_addObjectsFromArray_), 369) 370 371_index_sentinel=object() 372def index_indexOfObject_inRange_(self, item, start=0, stop=_index_sentinel): 373 #from Foundation import NSNotFound 374 NSNotFound = sys.maxsize 375 if start == 0 and stop is _index_sentinel: 376 res = self.indexOfObject_(container_wrap(item)) 377 if res == NSNotFound: 378 raise ValueError("%s.index(x): x not in list" % (type(self).__name__,)) 379 else: 380 l = len(self) 381 if start < 0: 382 start = l + start 383 if start < 0: 384 start = 0 385 386 if stop is not _index_sentinel: 387 if stop < 0: 388 stop = l + stop 389 if stop < 0: 390 stop = 0 391 else: 392 stop = l 393 394 itemcount = len(self) 395 396 if itemcount == 0: 397 raise ValueError("%s.index(x): x not in list" % (type(self).__name__,)) 398 399 else: 400 if start >= itemcount: 401 start = itemcount - 1 402 if stop >= itemcount: 403 stop = itemcount - 1 404 405 if stop <= start: 406 ln = 0 407 else: 408 409 ln = stop - start 410 411 412 if ln == 0: 413 raise ValueError("%s.index(x): x not in list" % (type(self).__name__,)) 414 415 if ln > sys.maxsize: 416 ln = sys.maxsize 417 418 res = self.indexOfObject_inRange_(item, (start, ln)) 419 if res == NSNotFound: 420 raise ValueError("%s.index(x): x not in list" % (type(self).__name__,)) 421 return res 422 423_CONVENIENCE_METHODS[b'indexOfObject:inRange:'] = ( 424 ('index', index_indexOfObject_inRange_), 425) 426 427def insert_insertObject_atIndex_(self, idx, item): 428 if idx < 0: 429 idx += len(self) 430 if idx < 0: 431 raise IndexError("list index out of range") 432 self.insertObject_atIndex_(container_wrap(item), idx) 433 434_CONVENIENCE_METHODS[b'insertObject:atIndex:'] = ( 435 ( 'insert', insert_insertObject_atIndex_), 436) 437 438if sys.version_info[0] == 2: 439 INT_TYPES = (int, long) 440 441else: 442 INT_TYPES = int 443 444def __getitem__objectAtIndex_(self, idx): 445 if isinstance(idx, slice): 446 start, stop, step = idx.indices(len(self)) 447 #if step == 1: 448 # m = getattr(self, 'subarrayWithRange_', None) 449 # if m is not None: 450 # return m((start, stop - start)) 451 return [self[i] for i in range(start, stop, step)] 452 453 elif not isinstance(idx, INT_TYPES): 454 raise TypeError("index must be a number") 455 456 if idx < 0: 457 idx += len(self) 458 if idx < 0: 459 raise IndexError("list index out of range") 460 461 return container_unwrap(self.objectAtIndex_(idx), RuntimeError) 462 463def __getslice__objectAtIndex_(self, i, j): 464 i = max(i, 0); j = max(j, 0) 465 return __getitem__objectAtIndex_(self, slice(i, j)) 466 467_CONVENIENCE_METHODS[b'objectAtIndex:'] = ( 468 ('__getitem__', __getitem__objectAtIndex_), 469 ('__getslice__', __getslice__objectAtIndex_), 470) 471 472def __delitem__removeObjectAtIndex_(self, idx): 473 if isinstance(idx, slice): 474 start, stop, step = idx.indices(len(self)) 475 if step == 1: 476 if start > stop: 477 start, stop = stop, start 478 m = getattr(self, 'removeObjectsInRange_', None) 479 if m is not None: 480 m((start, stop - start)) 481 return 482 r = reversed(range(start, stop, step)) 483 for i in r: 484 self.removeObjectAtIndex_(i) 485 return 486 if idx < 0: 487 idx += len(self) 488 if idx < 0: 489 raise IndexError("list index out of range") 490 491 self.removeObjectAtIndex_(idx) 492 493def __delslice__removeObjectAtIndex_(self, i, j): 494 __delitem__removeObjectAtIndex_(self, slice(i, j)) 495 496def pop_removeObjectAtIndex_(self, idx=-1): 497 length = len(self) 498 if length <= 0: 499 raise IndexError("pop from empty list") 500 elif idx >= length or (idx + length) < 0: 501 raise IndexError("pop index out of range") 502 elif idx < 0: 503 idx += len(self) 504 if idx < 0: 505 raise IndexError("list index out of range") 506 rval = self[idx] 507 self.removeObjectAtIndex_(idx) 508 return rval 509 510def remove_removeObjectAtIndex_(self, obj): 511 idx = self.index(obj) 512 self.removeObjectAtIndex_(idx) 513 514_CONVENIENCE_METHODS[b'removeObjectAtIndex:'] = ( 515 ('remove', remove_removeObjectAtIndex_), 516 ('pop', pop_removeObjectAtIndex_), 517 ('__delitem__', __delitem__removeObjectAtIndex_), 518 ('__delslice__', __delslice__removeObjectAtIndex_), 519) 520 521def __setitem__replaceObjectAtIndex_withObject_(self, idx, anObject): 522 if isinstance(idx, slice): 523 start, stop, step = idx.indices(len(self)) 524 if step >=0: 525 if stop <= start: 526 # Empty slice: insert values 527 stop = start 528 elif start <= stop: 529 start = stop 530 531 if step == 1: 532 m = getattr(self, 'replaceObjectsInRange_withObjectsFromArray_', None) 533 if m is not None: 534 m((start, stop - start), ensureArray(anObject)) 535 return 536 537 if not isinstance(anObject, (NSArray, list, tuple)): 538 anObject = list(anObject) 539 540 slice_len = len(range(start, stop, step)) 541 if slice_len != len(anObject): 542 raise ValueError("Replacing extended slice with %d elements by %d elements"%( 543 slice_len, len(anObject))) 544 545 if step > 0: 546 if anObject is self: 547 toAssign = list(anObject) 548 else: 549 toAssign = anObject 550 for inIdx, outIdx in enumerate(range(start, stop, step)): 551 self.replaceObjectAtIndex_withObject_(outIdx, toAssign[inIdx]) 552 553 elif step == 0: 554 raise ValueError("Step 0") 555 556 else: 557 if anObject is self: 558 toAssign = list(anObject) 559 else: 560 toAssign = anObject 561 for inIdx, outIdx in enumerate(range(start, stop, step)): 562 self.replaceObjectAtIndex_withObject_(outIdx, toAssign[inIdx]) 563 564 565 elif not isinstance(idx, INT_TYPES): 566 raise TypeError("index is not an integer") 567 568 else: 569 570 if idx < 0: 571 idx += len(self) 572 if idx < 0: 573 raise IndexError("list index out of range") 574 575 self.replaceObjectAtIndex_withObject_(idx, anObject) 576 577def __setslice__replaceObjectAtIndex_withObject_(self, i, j, seq): 578 i = max(i, 0) 579 j = max(j, 0) 580 __setitem__replaceObjectAtIndex_withObject_(self, slice(i, j), seq) 581 582_CONVENIENCE_METHODS[b'replaceObjectAtIndex:withObject:'] = ( 583 ('__setitem__', __setitem__replaceObjectAtIndex_withObject_), 584 ('__setslice__', __setslice__replaceObjectAtIndex_withObject_), 585) 586 587def enumeratorGenerator(anEnumerator): 588 while True: 589 yield container_unwrap(anEnumerator.nextObject(), StopIteration) 590 591def dictItems(aDict): 592 """ 593 NSDictionary.items() 594 """ 595 keys = aDict.allKeys() 596 return zip(keys, map(aDict.__getitem__, keys)) 597 598def itemsGenerator(aDict): 599 for key in aDict: 600 yield (key, aDict[key]) 601 602def __iter__objectEnumerator_keyEnumerator(self): 603 meth = getattr(self, 'keyEnumerator', None) 604 if meth is None: 605 meth = self.objectEnumerator 606 return iter(meth()) 607 608_CONVENIENCE_METHODS[b'keyEnumerator'] = ( 609 ('__iter__', __iter__objectEnumerator_keyEnumerator), 610) 611if sys.version_info[0] == 2: 612 _CONVENIENCE_METHODS[b'keyEnumerator'] += ( 613 ('iterkeys', lambda self: iter(self.keyEnumerator())), 614 ('iteritems', lambda self: itemsGenerator(self)), 615) 616 617_CONVENIENCE_METHODS[b'objectEnumerator'] = ( 618 ('__iter__', __iter__objectEnumerator_keyEnumerator), 619) 620 621if sys.version_info[0] == 2: 622 _CONVENIENCE_METHODS[b'objectEnumerator'] += ( 623 ('itervalues', lambda self: iter(self.objectEnumerator())), 624 ) 625 626_CONVENIENCE_METHODS[b'reverseObjectEnumerator'] = ( 627 ('__reversed__', lambda self: iter(self.reverseObjectEnumerator())), 628) 629 630_CONVENIENCE_METHODS[b'removeAllObjects'] = ( 631 ('clear', lambda self: self.removeAllObjects()), 632) 633 634_CONVENIENCE_METHODS[b'dictionaryWithDictionary:'] = ( 635 ('copy', lambda self: type(self).dictionaryWithDictionary_(self)), 636) 637 638_CONVENIENCE_METHODS[b'nextObject'] = ( 639 ('__iter__', enumeratorGenerator), 640) 641 642# 643# NSNumber seems to be and abstract base-class that is implemented using 644# NSCFNumber, a CoreFoundation 'proxy'. 645# 646NSNull = lookUpClass('NSNull') 647NSArray = lookUpClass('NSArray') 648#null = NSNull.null() 649 650number_wrap = repythonify 651 652def container_wrap(v): 653 if v is None: 654 return NSNull.null() 655 return v 656 657def container_unwrap(v, exc_type, *exc_args): 658 if v is None: 659 raise exc_type(*exc_args) 660 elif v is NSNull.null(): 661 return None 662 return v 663 664 665def fromkeys_dictionaryWithObjects_forKeys_(cls, keys, values=None): 666 if not isinstance(keys, (list, tuple)): 667 keys = list(keys) 668 if values is None: 669 values = (None,) * len(keys) 670 elif not isinstance(values, (list, tuple)): 671 values = list(values) 672 return cls.dictionaryWithObjects_forKeys_(values, keys) 673 674if sys.version_info[0] == 3: 675 def cmp(a, b): 676 if a == b: 677 return 0 678 elif a < b: 679 return -1 680 else: 681 return 1 682 683def sort(self, key=None, reverse=False, cmpfunc=cmp): 684 # NOTE: cmpfunc argument is for backward compatibility. 685 if key is None: 686 if reverse: 687 def doCmp(a, b, cmpfunc): 688 return -cmpfunc(a, b) 689 else: 690 def doCmp(a, b, cmpfunc): 691 return cmpfunc(a, b) 692 else: 693 # This is (a lot) slower than the algoritm used for 694 # list.sort, but so be it. 695 if reverse: 696 def doCmp(a, b, cmpfunc): 697 return -cmpfunc(key(a), key(b)) 698 else: 699 def doCmp(a, b, cmpfunc): 700 return cmpfunc(key(a), key(b)) 701 702 self.sortUsingFunction_context_(doCmp, cmpfunc) 703 704 705registerMetaDataForSelector(b"NSObject", b"sortUsingFunction:context:", 706 dict( 707 arguments={ 708 2: { 709 'callable': { 710 'reval': 'i', 711 'arguments': { 712 0: { 'type': b'@' }, 713 1: { 'type': b'@' }, 714 2: { 'type': b'@' }, 715 } 716 }, 717 'callable_retained': False, 718 }, 719 3: { 'type': b'@' }, 720 }, 721 )) 722 723 724_CONVENIENCE_METHODS[b'sortUsingFunction:context:'] = ( 725 ('sort', sort), 726) 727 728_CONVENIENCE_METHODS[b'hasPrefix:'] = ( 729 ('startswith', lambda self, pfx: self.hasPrefix_(pfx)), 730) 731 732_CONVENIENCE_METHODS[b'hasSuffix:'] = ( 733 ('endswith', lambda self, pfx: self.hasSuffix_(pfx)), 734) 735 736 737def __copy__(self): 738 if hasattr(self, 'mutableCopy'): 739 return self.mutableCopyWithZone_(None) 740 return self.copyWithZone_(None) 741_CONVENIENCE_METHODS[b'copyWithZone:'] = ( 742 ('__copy__', __copy__), 743) 744 745# This won't work: 746#NSKeyedArchiver = lookUpClass('NSKeyedArchiver') 747#NSKeyedUnarchiver = lookUpClass('NSKeyedUnarchiver') 748#def coder_deepcopy(self, memo): 749# buf = NSKeyedArchiver.archivedDataWithRootObject_(self) 750# result = NSKeyedUnarchiver.unarchiveObjectWithData_(buf) 751# return result 752# 753#_CONVENIENCE_METHODS['encodeWithCoder:'] = ( 754# ('__deepcopy__', coder_deepcopy ), 755#) 756 757CLASS_METHODS['NSNull'] = ( 758 ('__nonzero__', lambda self: False ), 759 ('__bool__', lambda self: False ), 760) 761 762NSDecimalNumber = lookUpClass('NSDecimalNumber') 763def _makeD(v): 764 if isinstance(v, NSDecimalNumber): 765 return v 766 767 return NSDecimalNumber.decimalNumberWithDecimal_(v) 768 769def decimal__add__(self, other): 770 return _makeD(self.decimalValue() + other) 771 772def decimal__radd__(self, other): 773 return _makeD(other + self.decimalValue()) 774 775CLASS_METHODS['NSDecimalNumber'] = ( 776 ('__add__', decimal__add__), 777 ('__radd__', decimal__radd__), 778 ('__sub__', lambda self, other: _makeD(self.decimalValue() - other)), 779 ('__rsub__', lambda self, other: _makeD(other - self.decimalValue())), 780 ('__mul__', lambda self, other: _makeD(self.decimalValue() * other)), 781 ('__rmul__', lambda self, other: _makeD(other * self.decimalValue())), 782 ('__div__', lambda self, other: _makeD(self.decimalValue() / other)), 783 ('__rdiv__', lambda self, other: _makeD(other / self.decimalValue())), 784 ('__truediv__', lambda self, other: _makeD(self.decimalValue() / other)), 785 ('__rtruediv__', lambda self, other: _makeD(other / self.decimalValue())), 786 ('__floordiv__', lambda self, other: _makeD(self.decimalValue() // other)), 787 ('__rfloordiv__', lambda self, other: _makeD(other // self.decimalValue())), 788 ('__mod__', lambda self, other: _makeD(self.decimalValue() % other)), 789 ('__rmod__', lambda self, other: _makeD(other % self.decimalValue())), 790 ('__neg__', lambda self: _makeD(-(self.decimalValue()))), 791 ('__pos__', lambda self: _makeD(+(self.decimalValue()))), 792 ('__abs__', lambda self: _makeD(abs(self.decimalValue()))), 793 ('__round__', lambda self, n=0 : _makeD(round(self.decimalValue(), n))), 794) 795 796def NSData__getslice__(self, i, j): 797 return self.bytes()[i:j] 798 799def NSData__getitem__(self, item): 800 buff = self.bytes() 801 try: 802 return buff[item] 803 except TypeError: 804 return buff[:][item] 805 806 807if sys.version_info[:2] <= (2,6): 808 def NSData__str__(self): 809 return self.bytes()[:] 810 811elif sys.version_info[0] == 2: 812 def NSData__str__(self): 813 return str(self.bytes().tobytes()) 814 815else: 816 def NSData__str__(self): 817 return str(self.bytes().tobytes()) 818 819 820CLASS_METHODS['NSData'] = ( 821 ('__str__', NSData__str__), 822 ('__getitem__', NSData__getitem__), 823 ('__getslice__', NSData__getslice__), 824) 825 826def NSMutableData__setslice__(self, i, j, sequence): 827 # XXX - could use replaceBytes:inRange:, etc. 828 self.mutableBytes()[i:j] = sequence 829 830def NSMutableData__setitem__(self, item, value): 831 self.mutableBytes()[item] = value 832 833CLASS_METHODS['NSMutableData'] = ( 834 ('__setslice__', NSMutableData__setslice__), 835 ('__setitem__', NSMutableData__setitem__), 836) 837 838 839def __call__(self, *args, **kwds): 840 return _block_call(self, self.__block_signature__, args, kwds) 841 842CLASS_METHODS['NSBlock'] = ( 843 ('__call__', __call__), 844) 845 846 847if sys.version_info[0] == 3 or (sys.version_info[0] == 2 and sys.version_info[1] >= 6): 848 849 def all_contained_in(inner, outer): 850 """ 851 Return True iff all items in ``inner`` are also in ``outer``. 852 """ 853 for v in inner: 854 if v not in outer: 855 return False 856 857 return True 858 859 class nsdict_view (collections.Set): 860 __slots__ = () 861 862 def __eq__(self, other): 863 if not isinstance(other, collections.Set): 864 return NotImplemented 865 866 if len(self) == len(other): 867 return all_contained_in(self, other) 868 869 else: 870 return False 871 872 def __ne__(self, other): 873 if not isinstance(other, collections.Set): 874 return NotImplemented 875 876 if len(self) == len(other): 877 return not all_contained_in(self, other) 878 879 else: 880 return True 881 882 def __lt__(self, other): 883 if not isinstance(other, collections.Set): 884 return NotImplemented 885 886 if len(self) < len(other): 887 return all_contained_in(self, other) 888 889 else: 890 return False 891 892 def __le__(self, other): 893 if not isinstance(other, collections.Set): 894 return NotImplemented 895 896 if len(self) <= len(other): 897 return all_contained_in(self, other) 898 899 else: 900 return False 901 902 def __gt__(self, other): 903 if not isinstance(other, collections.Set): 904 return NotImplemented 905 906 if len(self) > len(other): 907 return all_contained_in(other, self) 908 909 else: 910 return False 911 912 def __ge__(self, other): 913 if not isinstance(other, collections.Set): 914 return NotImplemented 915 916 if len(self) >= len(other): 917 return all_contained_in(other, self) 918 919 else: 920 return False 921 922 def __and__(self, other): 923 if not isinstance(other, collections.Set): 924 return NotImplemented 925 result = set(self) 926 result.intersection_update(other) 927 return result 928 929 def __or__(self, other): 930 if not isinstance(other, collections.Set): 931 return NotImplemented 932 result = set(self) 933 result.update(other) 934 return result 935 936 def __ror__(self, other): 937 if not isinstance(other, collections.Set): 938 return NotImplemented 939 result = set(self) 940 result.update(other) 941 return result 942 943 def __sub__(self, other): 944 if not isinstance(other, collections.Set): 945 return NotImplemented 946 result = set(self) 947 result.difference_update(other) 948 return result 949 950 def __xor__(self, other): 951 if not isinstance(other, collections.Set): 952 return NotImplemented 953 result = set(self) 954 result.symmetric_difference_update(other) 955 return result 956 957 #collections.Set.register(nsdict_view) 958 959 class nsdict_keys(nsdict_view): 960 __slots__=('__value') 961 def __init__(self, value): 962 self.__value = value 963 964 def __repr__(self): 965 keys = list(self.__value) 966 #keys.sort() 967 968 return "<nsdict_keys({0})>".format(keys) 969 970 971 def __len__(self): 972 return len(self.__value) 973 974 def __iter__(self): 975 return iter(self.__value) 976 977 def __contains__(self, value): 978 return value in self.__value 979 980 class nsdict_values(nsdict_view): 981 __slots__=('__value') 982 def __init__(self, value): 983 self.__value = value 984 985 def __repr__(self): 986 values = list(self) 987 values.sort() 988 989 return "<nsdict_values({0})>".format(values) 990 991 def __len__(self): 992 return len(self.__value) 993 994 def __iter__(self): 995 return iter(self.__value.objectEnumerator()) 996 997 def __contains__(self, value): 998 for v in iter(self): 999 if value == v: 1000 return True 1001 return False 1002 1003 class nsdict_items(nsdict_view): 1004 1005 __slots__=('__value') 1006 1007 def __init__(self, value): 1008 self.__value = value 1009 1010 def __repr__(self): 1011 values = list(self) 1012 values.sort() 1013 1014 return "<nsdict_items({0})>".format(values) 1015 1016 def __len__(self): 1017 return len(self.__value) 1018 1019 def __iter__(self): 1020 for k in self.__value: 1021 yield (k, self.__value[k]) 1022 1023 def __contains__(self, value): 1024 for v in iter(self): 1025 if value == v: 1026 return True 1027 return False 1028 1029 collections.KeysView.register(nsdict_keys) 1030 collections.ValuesView.register(nsdict_values) 1031 collections.ItemsView.register(nsdict_items) 1032 1033 collections.Mapping.register(lookUpClass('NSDictionary')) 1034 collections.MutableMapping.register(lookUpClass('NSMutableDictionary')) 1035 1036 1037 1038 NSDictionary = lookUpClass('NSDictionary') 1039 def nsdict_fromkeys(cls, keys, value=None): 1040 keys = [container_wrap(k) for k in keys] 1041 values = [container_wrap(value)]*len(keys) 1042 1043 return NSDictionary.dictionaryWithObjects_forKeys_(values, keys) 1044 1045 NSMutableDictionary = lookUpClass('NSMutableDictionary') 1046 def nsmutabledict_fromkeys(cls, keys, value=None): 1047 result = NSMutableDictionary.dictionary() 1048 value = container_wrap(value) 1049 for k in keys: 1050 result[container_wrap(k)] = value 1051 1052 return result 1053 1054 def dict_new(cls, args, kwds): 1055 if len(args) == 0: 1056 pass 1057 1058 elif len(args) == 1: 1059 d = dict() 1060 if isinstance(args[0], collections.Mapping): 1061 items = args[0].items() 1062 else: 1063 items = args[0] 1064 for k , v in items: 1065 d[container_wrap(k)] = container_wrap(v) 1066 1067 for k, v in kwds.items(): 1068 d[container_wrap(k)] = container_wrap(v) 1069 1070 return cls.dictionaryWithDictionary_(d) 1071 1072 else: 1073 raise TypeError( 1074 "dict expected at most 1 arguments, got {0}".format( 1075 len(args))) 1076 if kwds: 1077 d = dict() 1078 for k, v in kwds.items(): 1079 d[container_wrap(k)] = container_wrap(v) 1080 1081 return cls.dictionaryWithDictionary_(d) 1082 1083 return cls.dictionary() 1084 1085 def nsdict_new(cls, *args, **kwds): 1086 return dict_new(NSDictionary, args, kwds) 1087 1088 def nsmutabledict_new(cls, *args, **kwds): 1089 return dict_new(NSMutableDictionary, args, kwds) 1090 1091 1092 def nsdict__eq__(self, other): 1093 if not isinstance(other, collections.Mapping): 1094 return False 1095 1096 return self.isEqualToDictionary_(other) 1097 1098 def nsdict__ne__(self, other): 1099 return not nsdict__eq__(self, other) 1100 1101 def nsdict__richcmp__(self, other): 1102 return NotImplemented 1103 1104 1105 if sys.version_info[0] == 3: 1106 CLASS_METHODS['NSDictionary'] = ( 1107 ('fromkeys', classmethod(nsdict_fromkeys)), 1108 ('keys', lambda self: nsdict_keys(self)), 1109 ('values', lambda self: nsdict_values(self)), 1110 ('items', lambda self: nsdict_items(self)), 1111 1112 # Explicitly add these methods, instead of relying 1113 # on the selector based selection. 1114 # 1115 # Primary reason: turns out at least the chosen 1116 # implementation for __contains__ depends on dict 1117 # iteration order, and one of the implementation doesn't 1118 # work for NSDictionary. 1119 # 1120 # In the slightly longer run all python API 1121 # implementations will be added explictly to 1122 # classes because of this, and because this allows 1123 # for a faster implementation of method dispatch. 1124 ('__getitem__', __getitem__objectForKey_), 1125 ('get', get_objectForKey_), 1126 ('__contains__', has_key_objectForKey_), 1127 ) 1128 1129 CLASS_METHODS['NSMutableDictionary'] = ( 1130 ('fromkeys', classmethod(nsmutabledict_fromkeys)), 1131 ) 1132 1133 else: 1134 CLASS_METHODS['NSDictionary'] = ( 1135 ('fromkeys', classmethod(nsdict_fromkeys)), 1136 ('viewkeys', lambda self: nsdict_keys(self)), 1137 ('viewvalues', lambda self: nsdict_values(self)), 1138 ('viewitems', lambda self: nsdict_items(self)), 1139 ('keys', lambda self: self.allKeys()), 1140 ('items', lambda self: dictItems(self)), 1141 ('values', lambda self: self.allValues()), 1142 ('__getitem__', __getitem__objectForKey_), 1143 ('get', get_objectForKey_), 1144 ('__contains__', has_key_objectForKey_), 1145 ('has_key', has_key_objectForKey_), 1146 ) 1147 1148 CLASS_METHODS['NSDictionary'] += ( 1149 ('__eq__', nsdict__eq__), 1150 ('__ne__', nsdict__ne__), 1151 ('__lt__', nsdict__richcmp__), 1152 ('__le__', nsdict__richcmp__), 1153 ('__gt__', nsdict__richcmp__), 1154 ('__ge__', nsdict__richcmp__), 1155 ) 1156 1157 NSDictionary.__new__ = nsdict_new 1158 NSMutableDictionary.__new__ = nsmutabledict_new 1159 1160 NSMutableDictionary.dictionary() 1161 1162 #FIXME: This shouldn't be necessary 1163 1164NSMutableArray = lookUpClass('NSMutableArray') 1165def nsarray_add(self, other): 1166 result = NSMutableArray.arrayWithArray_(self) 1167 result.extend(other) 1168 return result 1169 1170def nsarray_radd(self, other): 1171 result = NSMutableArray.arrayWithArray_(other) 1172 result.extend(self) 1173 return result 1174 1175def nsarray_mul(self, other): 1176 """ 1177 This tries to implement anNSArray * N 1178 somewhat efficently (and definitely more 1179 efficient that repeated appending). 1180 """ 1181 result = NSMutableArray.array() 1182 1183 if other <= 0: 1184 return result 1185 1186 n = 1 1187 tmp = self 1188 while other: 1189 if other & n != 0: 1190 result.extend(tmp) 1191 other -= n 1192 1193 if other: 1194 n <<= 1 1195 tmp = tmp.arrayByAddingObjectsFromArray_(tmp) 1196 1197 return result 1198 1199 1200 1201def nsarray_new(cls, sequence=None): 1202 if not sequence: 1203 return NSArray.array() 1204 1205 elif isinstance(sequence, STR_TYPES): 1206 return NSArray.arrayWithArray_(list(sequence)) 1207 1208 else: 1209 if not isinstance(sequence, (list, tuple)): 1210 # FIXME: teach bridge to treat range and other list-lik 1211 # types correctly 1212 return NSArray.arrayWithArray_(list(sequence)) 1213 1214 return NSArray.arrayWithArray_(sequence) 1215 1216if sys.version_info[0] == 2: 1217 STR_TYPES=(str, unicode) 1218else: 1219 STR_TYPES=str 1220 1221def nsmutablearray_new(cls, sequence=None): 1222 if not sequence: 1223 return NSMutableArray.array() 1224 1225 elif isinstance(sequence, STR_TYPES): 1226 return NSMutableArray.arrayWithArray_(list(sequence)) 1227 1228 else: 1229 if not isinstance(sequence, (list, tuple)): 1230 # FIXME: teach bridge to treat range and other list-lik 1231 # types correctly 1232 return NSMutableArray.arrayWithArray_(list(sequence)) 1233 1234 return NSMutableArray.arrayWithArray_(sequence) 1235 1236CLASS_METHODS['NSArray'] = ( 1237 ('__add__', nsarray_add), 1238 ('__radd__', nsarray_radd), 1239 ('__mul__', nsarray_mul), 1240 ('__rmul__', nsarray_mul), 1241) 1242 1243# Force scans to ensure __new__ is set correctly 1244# FIXME: This shouldn't be necessary! 1245NSArray.__new__ = nsarray_new 1246NSMutableArray.__new__ = nsmutablearray_new 1247NSMutableArray.alloc().init() 1248#NSMutableSet.set() 1249 1250NSSet = lookUpClass('NSSet') 1251NSMutableSet = lookUpClass('NSMutableSet') 1252 1253try: 1254 from collections import Set 1255 Set.register(NSSet) 1256except: 1257 Set = (set, frozenset, NSSet) 1258 1259def nsset_isdisjoint(self, other): 1260 for item in self: 1261 if item in other: 1262 return False 1263 return True 1264 1265def nsset_union(self, *other): 1266 result = NSMutableSet() 1267 result.unionSet_(self) 1268 for val in other: 1269 if isinstance(val, Set): 1270 result.unionSet_(val) 1271 else: 1272 result.unionSet_(set(val)) 1273 return result 1274 1275def nsset_intersection(self, *others): 1276 if len(others) == 0: 1277 return self.mutableCopy() 1278 result = NSMutableSet() 1279 for item in self: 1280 for o in others: 1281 if item not in o: 1282 break 1283 else: 1284 result.add(item) 1285 return result 1286 1287def nsset_difference(self, *others): 1288 result = self.mutableCopy() 1289 1290 for value in others: 1291 if isinstance(value, Set): 1292 result.minusSet_(value) 1293 else: 1294 result.minusSet_(set(value)) 1295 1296 return result 1297 1298def nsset_symmetric_difference(self, other): 1299 result = NSMutableSet() 1300 for item in self: 1301 if item not in other: 1302 result.add(item) 1303 for item in other: 1304 if item not in self: 1305 result.add(item) 1306 return result 1307 1308 1309def nsset__contains__(self, value): 1310 hash(value) # Force error for non-hashable values 1311 return self.containsObject_(value) 1312 1313def nsset__or__(self, other): 1314 if not isinstance(self, Set): 1315 raise TypeError("NSSet|value where value is not a set") 1316 if not isinstance(other, Set): 1317 raise TypeError("NSSet|value where value is not a set") 1318 return nsset_union(self, other) 1319 1320def nsset__ror__(self, other): 1321 if not isinstance(self, Set): 1322 raise TypeError("value|NSSet where value is not a set") 1323 if not isinstance(other, Set): 1324 raise TypeError("value|NSSet where value is not a set") 1325 return nsset_union(other, self) 1326 1327def nsset__and__(self, other): 1328 if not isinstance(self, Set): 1329 raise TypeError("NSSet&value where value is not a set") 1330 if not isinstance(other, Set): 1331 raise TypeError("NSSet&value where value is not a set") 1332 return nsset_intersection(self, other) 1333 1334def nsset__rand__(self, other): 1335 if not isinstance(self, Set): 1336 raise TypeError("value&NSSet where value is not a set") 1337 if not isinstance(other, Set): 1338 raise TypeError("value&NSSet where value is not a set") 1339 return nsset_intersection(other, self) 1340 1341def nsset__sub__(self, other): 1342 if not isinstance(self, Set): 1343 raise TypeError("NSSet-value where value is not a set") 1344 if not isinstance(other, Set): 1345 raise TypeError("NSSet-value where value is not a set") 1346 return nsset_difference(self, other) 1347 1348def nsset_rsub__(self, other): 1349 if not isinstance(self, Set): 1350 raise TypeError("NSSet-value where value is not a set") 1351 if not isinstance(other, Set): 1352 raise TypeError("NSSet-value where value is not a set") 1353 return nsset_difference(other, self) 1354 1355def nsset__xor__(self, other): 1356 if not isinstance(self, Set): 1357 raise TypeError("NSSet-value where value is not a set") 1358 if not isinstance(other, Set): 1359 raise TypeError("NSSet-value where value is not a set") 1360 return nsset_symmetric_difference(other, self) 1361 1362def nsset_issubset(self, other): 1363 if isinstance(other, Set): 1364 return self.isSubsetOfSet_(other) 1365 1366 else: 1367 return self.isSubsetOfSet_(set(other)) 1368 1369def nsset__le__(self, other): 1370 if not isinstance(other, Set): 1371 raise TypeError() 1372 return nsset_issubset(self, other) 1373 1374def nsset__eq__(self, other): 1375 if not isinstance(other, Set): 1376 return False 1377 1378 return self.isEqualToSet_(other) 1379 1380def nsset__ne__(self, other): 1381 if not isinstance(other, Set): 1382 return True 1383 1384 return not self.isEqualToSet_(other) 1385 1386def nsset__lt__(self, other): 1387 if not isinstance(other, Set): 1388 raise TypeError() 1389 1390 return (self <= other) and (self != other) 1391 1392def nsset_issuperset(self, other): 1393 if not isinstance(other, Set): 1394 other = set(other) 1395 1396 for item in other: 1397 if item not in self: 1398 return False 1399 1400 return True 1401 1402def nsset__ge__(self, other): 1403 if not isinstance(other, Set): 1404 raise TypeError() 1405 return nsset_issuperset(self, other) 1406 1407def nsset__gt__(self, other): 1408 if not isinstance(other, Set): 1409 raise TypeError() 1410 return (self >= other) and (self != other) 1411 1412if sys.version_info[0] == 2: 1413 def nsset__cmp__(self, other): 1414 raise TypeError("Cannot compare sets using cmp") 1415 1416def nsset__length_hint__(self): 1417 return len(self) 1418 1419def nsset_update(self, *others): 1420 for other in others: 1421 if isinstance(other, Set): 1422 self.unionSet_(other) 1423 else: 1424 self.unionSet_(set(other)) 1425 1426def nsset_intersection_update(self, *others): 1427 for other in others: 1428 if isinstance(other, Set): 1429 self.intersectSet_(other) 1430 else: 1431 self.intersectSet_(set(other)) 1432 1433def nsset_difference_update(self, *others): 1434 for other in others: 1435 if isinstance(other, Set): 1436 self.minusSet_(other) 1437 else: 1438 self.minusSet_(set(other)) 1439 1440def nsset_symmetric_difference_update(self, other): 1441 toadd = set() 1442 toremove = set() 1443 1444 if isinstance(other, Set): 1445 totest = other 1446 else: 1447 totest = set(other) 1448 1449 for value in self: 1450 if value in totest: 1451 toremove.add(value) 1452 for value in totest: 1453 if value not in self: 1454 toadd.add(value) 1455 1456 self.minusSet_(toremove) 1457 self.unionSet_(toadd) 1458 1459def nsset_pop(self): 1460 if len(self) == 0: 1461 raise KeyError() 1462 1463 v = self.anyObject() 1464 self.removeObject_(v) 1465 return container_unwrap(v, KeyError) 1466 1467def nsset_remove(self, value): 1468 hash(value) 1469 value = container_wrap(value) 1470 if value not in self: 1471 raise KeyError(value) 1472 self.removeObject_(value) 1473 1474def nsset_discard(self, value): 1475 hash(value) 1476 self.removeObject_(container_wrap(value)) 1477 1478def nsset_add(self, value): 1479 hash(value) 1480 self.addObject_(container_wrap(value)) 1481 1482class nsset__iter__ (object): 1483 def __init__(self, value): 1484 self._size = len(value) 1485 self._enum = value.objectEnumerator() 1486 1487 def __length_hint__(self): 1488 return self._size 1489 1490 def __iter__(self): 1491 return self 1492 1493 def __next__(self): 1494 self._size -= 1 1495 return container_unwrap(self._enum.nextObject(), StopIteration) 1496 1497 next = __next__ 1498 1499 1500 1501 1502CLASS_METHODS['NSSet'] = ( 1503 ('__iter__', lambda self: nsset__iter__(self)), 1504 ('__length_hint__', nsset__length_hint__), 1505 ('__contains__', nsset__contains__), 1506 ('isdisjoint', nsset_isdisjoint), 1507 ('union', nsset_union), 1508 ('intersection', nsset_intersection), 1509 ('difference', nsset_difference), 1510 ('symmetric_difference', nsset_symmetric_difference), 1511 ('issubset', nsset_issubset), 1512 ('__eq__', nsset__eq__), 1513 ('__ne__', nsset__ne__), 1514 ('__le__', nsset__le__), 1515 ('__lt__', nsset__lt__), 1516 ('issuperset', nsset_issuperset), 1517 ('__ge__', nsset__ge__), 1518 ('__gt__', nsset__gt__), 1519 ('__or__', nsset__or__), 1520 ('__ror__', nsset__ror__), 1521 ('__and__', nsset__and__), 1522 ('__rand__', nsset__rand__), 1523 ('__xor__', nsset__xor__), 1524 ('__rxor__', nsset__xor__), 1525 ('__sub__', nsset__sub__), 1526) 1527 1528if sys.version_info[0] == 2: 1529 CLASS_METHODS['NSSet'] += ( 1530 ('__cmp__', nsset__cmp__), 1531 ) 1532 1533CLASS_METHODS['NSMutableSet'] = ( 1534 ('add', nsset_add), 1535 ('remove', nsset_remove), 1536 ('discard', nsset_discard), 1537 ('update', nsset_update), 1538 ('intersection_update', nsset_intersection_update), 1539 ('difference_update', nsset_difference_update), 1540 ('symmetric_difference_update', nsset_symmetric_difference_update), 1541 ('clear', lambda self: self.removeAllObjects()), 1542 ('pop', nsset_pop), 1543) 1544 1545def nsset_new(cls, sequence=None): 1546 if not sequence: 1547 return NSSet.set() 1548 1549 if isinstance(sequence, (NSSet, set, frozenset)): 1550 return NSSet.set().setByAddingObjectsFromSet_(sequence) 1551 1552 else: 1553 return NSSet.set().setByAddingObjectsFromSet_(set(sequence)) 1554 1555def nsmutableset_new(cls, sequence=None): 1556 if not sequence: 1557 value = NSMutableSet.set() 1558 1559 elif isinstance(sequence, (NSSet, set, frozenset)): 1560 value = NSMutableSet.set() 1561 value.unionSet_(sequence) 1562 1563 else: 1564 value = NSMutableSet.set() 1565 value.unionSet_(set(sequence)) 1566 1567 return value 1568 1569NSSet.__new__ = nsset_new 1570NSMutableSet.__new__ = nsmutableset_new 1571 1572NSMutableSet.alloc().init() 1573