zoukankan      html  css  js  c++  java
  • Day9---Python训练营

    主要内容是魔法方法。

    魔法方法总是被双下划线包围,例如 __init__ 。
    魔法方法是面向对象的 Python 的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的 Python 的强大。 魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。
    魔法方法的第一个参数应为 cls (类方法) 或者 self (实例方法)。
    1. cls:代表一个类的名称
    2. self:代表一个实例对象的名称

    一、基本的魔法方法

    __init__(self[,...])

    1. 构造器,当一个实例被创建的时候调用的初始化方法。

    __new__(cls[, ...])
    1. __new__ 是在一个对象实例化的时候所调用的第一个方法,在调用 __init__ 初始化前,先调用 __new__ 。
    2. __new__ 至少要有一个参数 cls ,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直
    接传递给 __init__ 。
    3. __new__ 对当前类进行了实例化,并将实例返回,传给 __init__ 的 self 。但是,执行了 __new__ ,并不一定会
    进入 __init__ ,只有 __new__ 返回了,当前类 cls 的实例,当前类的 __init__ 才会进入。

     1 class A(object):
     2     def __init__(self, value):
     3         print("into A __init__" )
     4         self.value = value
     5     def __new__(cls, *args, **kwargs):
     6         print("into A __new__")
     7         print(cls)
     8         return object.__new__( cls)
     9 
    10 class B(A):
    11     def __init__(self, value):
    12         print("into B __init__" )
    13         self.value = value
    14         
    15     def __new__(cls, *args, **kwargs):
    16         print("into B __new__")
    17         print(cls)
    18         return super().__new__(cls, *args, **kwargs)   
    19 b=B(10)
    20 
    21 into B __new__
    22 <class '__main__.B'>
    23 into A __new__
    24 <class '__main__.B'>
    25 into B __init__
    class A(object):
        def __init__(self, value):
            print("into A __init__" )
            self.value = value
        def __new__(cls, *args, **kwargs):
            print("into A __new__")
            print(cls)
            return object.__new__( cls)
        
    class B(A):
        def __init__(self, value):
            print("into B __init__" )
            self.value = value
        def __new__(cls, *args, **kwargs):
            print("into B __new__")
            print(cls)
            return super().__new__(A, *args, **kwargs) # 改动了cls变为A
    
    b = B(10)
    
    into B __new__
    <class '__main__.B'>
    into A __new__
    <class '__main__.A'>

    若 __new__ 没有正确返回当前类 cls 的实例,那 __init__ 是不会被调用的,即使是父类的实例也不行,将没有 __init__ 被调用。
    可利用 __new__ 实现单例模式。

     1 class Earth:
     2      pass
     3 a = Earth()
     4 print(id(a))  #2608415619168
     5 b = Earth()
     6 print(id(b))  #2608415620904
     7 
     8 class Earth:
     9     __instance = None # 定义一个类属性做判断
    10 
    11     def __new__(cls):
    12         if cls.__instance is None:
    13             cls.__instance = object.__new__( cls)
    14             return cls.__instance
    15         else:
    16             return cls.__instance
    17 a = Earth()
    18 print(id(a)) #2608415548304
    19 b = Earth()
    20 print(id(b)) # 2608415548304

    __new__ 方法主要是当你继承一些不可变的 class 时(比如 int, str, tuple ), 提供给你一个自定义这些类的实例化过程的途径。

    1 class CapStr(str):
    2     def __new__(cls, string):
    3         string = string.upper()
    4         return str.__new__(cls, string)
    5 
    6 a = CapStr("i love lsgogroup" )
    7 print(a)   #I LOVE LSGOGROUP

    __del__(self)
    析构器,当一个对象将要被系统回收之时调用的方法。
    Python 采用自动引用计数( ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时, Python会自动保证该对象引用计数为 1;当程序中有两个变量引用该 Python 对象时, Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此Python 就会回收该对象。
    大部分时候, Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,比如对象a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器( Cyclic Garbage Collector)来检测并回收这种引用循环。

     1 class C(object):
     2     def __init__(self):
     3         print('into C __init__' )
     4     def __del__(self):
     5         print('into C __del__' )
     6         
     7 c1 = C()   # into C __init__
     8 
     9 c2 = c1
    10 c3 = c2
    11 del c3
    12 del c2
    13 del c1  #into C __del__ 

    __str__ __repr__
    __str__(self) :
    1. 当你打印一个对象的时候,触发 __str__
    2. 当你使用 %s 格式化的时候,触发 __str__
    3. str 强转数据类型的时候,触发 __str__
    __repr__(self):
    1. repr 是 str 的备胎
    2. 有 __str__ 的时候执行 __str__ ,没有实现 __str__ 的时候,执行 __repr__
    3. repr(obj) 内置函数对应的结果是 __repr__ 的返回值
    4. 当你使用 %r 格式化的时候触发 __repr__

     1 class Cat:
     2     """定义一个猫类"""
     3  
     4     def __init__(self, new_name, new_age):
     5         """在创建完对象之后 会自动调用 , 它完成对象的初始化的功能""" 
     6         self.name = new_name
     7         self.age = new_age
     8         
     9     def __str__(self):
    10         return "名字是:%s , 年龄是:%d" % (self.name, self.age)
    11     
    12     def __repr__(self):
    13         return "Cat:(%s,%d)"  %( self.name,self.age)
    14     
    15     def eat(self):
    16         print("%s在吃鱼...." % self.name)
    17         
    18     def drink(self):
    19         print("%s在喝可乐..." % self.name)
    20    
    21     def introduce(self):
    22          print("名字是:%s, 年龄是:%d" % (self.name, self.age))
    23 
    24 # 创建了一个对象
    25 tom = Cat("汤姆", 30)
    26 print(tom)   # 名字是:汤姆 , 年龄是:30
    27 
    28 print(str(tom))  #名字是:汤姆 , 年龄是:30
    29 
    30 print(repr(tom)) #Cat:(汤姆,30)
    31 
    32 tom.eat() # 汤姆在吃鱼....
    33 
    34 tom.introduce() #名字是:汤姆, 年龄是:30 

    __str__(self) 的返回结果可读性强。也就是说, __str__ 的意义是得到便于人们阅读的信息,就像下面的 '2019-10-11' 一样。
    __repr__(self) 的返回结果应更准确。怎么说, __repr__ 存在的目的在于调试,便于开发者使用。

    1 import datetime
    2 today = datetime.date.today()
    3 print(str(today)) #2020-12-31
    4 
    5 print(repr(today)) # datetime.date(2020, 12, 31)
    6 
    7 print('%s'  %today)  #2020-12-31
    8 
    9 print('%r'  %today) #datetime.date(2020, 12, 31)

    二、算术运算符
       类型工厂函数,指的是不通过类而是通过函数来创建对象。

     1 class C:
     2     pass
     3 
     4 print(type(len)) #<class 'builtin_function_or_method'>
     5 
     6 print(type(dir)) #<class 'builtin_function_or_method'>
     7 
     8 print(type(int)) #<class 'type'>
     9 
    10 print(type(list)) # <class 'type'>
    11 
    12 print(type(tuple)) #<class 'type'>
    13 
    14 print(type(C)) #<class 'type'>
    15 
    16 print(int('123' ))  #123
    17 
    18 # 这个例子中list工厂函数把一个元祖对象加工成了一个列表对象。
    19 print(list((1, 2, 3))) #[1, 2, 3]

    1. __add__(self, other) 定义加法的行为: +
    2. __sub__(self, other) 定义减法的行为: -

    class MyClass:
        def __init__(self, height, weight):
            self.height = height
            self.weight = weight
        
        # 两个对象的长相加,宽不变. 返回一个新的类
        def __add__(self, others):
            return MyClass( self.height + others.height, self.weight + others.weight)
        
        # 两个对象的宽相减,长不变. 返回一个新的类
        def __sub__(self, others):
            return MyClass( self.height - others.height, self.weight - others.weight)
        
        def intro(self):
            print("高为", self.height, " 重为", self.weight)
    
    def main():
        a = MyClass(height=10, weight=5)
        a.intro()
        b = MyClass(height=20, weight=10)
        b.intro()
        c = b - a
        c.intro()
        d = a + b
        d.intro()
    if __name__ == '__main__':
        main()
    
    高为 10  重为 5
    高为 20  重为 10
    高为 10  重为 5
    高为 30  重为 15

    1. __mul__(self, other) 定义乘法的行为: *
    2. __truediv__(self, other) 定义真除法的行为: /
    3. __floordiv__(self, other) 定义整数除法的行为: //
    4. __mod__(self, other) 定义取模算法的行为: %
    5. __divmod__(self, other) 定义当被 divmod() 调用时的行为
    6. divmod(a, b) 把除数和余数运算结果结合起来,返回一个包含商和余数的元组 (a // b, a % b) 。

    1 print(divmod(7, 2)) #(3, 1)
    2 print(divmod(8, 2)) #(4, 0)

    1. __pow__(self, other[, module]) 定义当被 power() 调用或 ** 运算时的行为
    2. __lshift__(self, other) 定义按位左移位的行为: <<
    3. __rshift__(self, other) 定义按位右移位的行为: >>
    4. __and__(self, other) 定义按位与操作的行为: &
    5. __xor__(self, other) 定义按位异或操作的行为: ^
    6. __or__(self, other) 定义按位或操作的行为: |
    三、反算术运算符
    反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。
    1. __radd__(self, other) 定义加法的行为: +
    2. __rsub__(self, other) 定义减法的行为: -
    3. __rmul__(self, other) 定义乘法的行为: *
    4. __rtruediv__(self, other) 定义真除法的行为: /
    5. __rfloordiv__(self, other) 定义整数除法的行为: //
    6. __rmod__(self, other) 定义取模算法的行为: %
    7. __rdivmod__(self, other) 定义当被 divmod() 调用时的行为
    8. __rpow__(self, other[, module]) 定义当被 power() 调用或 ** 运算时的行为
    9. __rlshift__(self, other) 定义按位左移位的行为: <<
    10. __rrshift__(self, other) 定义按位右移位的行为: >>
    11. __rand__(self, other) 定义按位与操作的行为: &
    12. __rxor__(self, other) 定义按位异或操作的行为: ^
    13. __ror__(self, other) 定义按位或操作的行为: |
    a + b
    这里加数是 a ,被加数是 b ,因此是 a 主动,反运算就是如果 a 对象的 __add__() 方法没有实现或者不支持相应的操
    作,那么 Python 就会调用 b 的 __radd__() 方法。

    1 class Nint(int):
    2     def __radd__(self, other):
    3         return int.__sub__(other, self) # 注意 self 在后面
    4 
    5 a = Nint(5)
    6 b = Nint(3)
    7 print(a + b)#8
    8 print(1 + b)#-2

    四、增量赋值运算符
    1. __iadd__(self, other) 定义赋值加法的行为: +=
    2. __isub__(self, other) 定义赋值减法的行为: -=
    3. __imul__(self, other) 定义赋值乘法的行为: *=
    4. __itruediv__(self, other) 定义赋值真除法的行为: /=
    5. __ifloordiv__(self, other) 定义赋值整数除法的行为: //=
    6. __imod__(self, other) 定义赋值取模算法的行为: %=
    7. __ipow__(self, other[, modulo]) 定义赋值幂运算的行为: **=
    8. __ilshift__(self, other) 定义赋值按位左移位的行为: <<=
    9. __irshift__(self, other) 定义赋值按位右移位的行为: >>=
    10. __iand__(self, other) 定义赋值按位与操作的行为: &=
    11. __ixor__(self, other) 定义赋值按位异或操作的行为: ^=
    12. __ior__(self, other) 定义赋值按位或操作的行为: |=
    五、一元运算符
    1. __neg__(self) 定义正号的行为: +x
    2. __pos__(self) 定义负号的行为: -x
    3. __abs__(self) 定义当被 abs() 调用时的行为
    4. __invert__(self) 定义按位求反的行为: ~x
    六、属性访问
    __getattr__ __getattribute__ __setattr__ __delattr__
    __getattr__(self, name) : 定义当用户试图获取一个不存在的属性时的行为。
    __getattribute__(self, name) :定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用 __getattr__ )。
    __setattr__(self, name, value) :定义当一个属性被设置时的行为。
    __delattr__(self, name) :定义当一个属性被删除时的行为。

    class C:
        def __getattribute__( self, item):
            print('__getattribute__' )
            return super().__getattribute__(item)
        def __getattr__(self, item):
            print('__getattr__' )
        def __setattr__(self, key, value):
            print('__setattr__' )
            super().__setattr__(key, value)
            
        def __delattr__(self, item):
            print('__delattr__' )
            super().__delattr__(item)
            
    c = C()
    c.x
    #__getattribute__
    #__getattr__
    
    c.x = 1
    #__setattr__
    
    del c.x
    #__delattr__

    七、描述符

    描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
    1. __get__(self, instance, owner) 用于访问属性,它返回属性的值。
    2. __set__(self, instance, value) 将在属性分配操作中调用,不返回任何内容。
    3. __del__(self, instance) 控制删除操作,不返回任何内容。

     1 class MyDecriptor:
     2     def __get__(self, instance, owner):
     3         print('__get__' , self, instance, owner)
     4         
     5     def __set__(self, instance, value):
     6         print('__set__' , self, instance, value)
     7         
     8     def __delete__(self, instance):
     9         print('__delete__' , self, instance)
    10 class Test:
    11     x = MyDecriptor()
    12 t = Test()
    13 t.x
    14 #__get__ <__main__.MyDecriptor object at 0x0000025F51B03B70> <__main__.Test object at 0x0000025F51B37048> <class '__main__.Test'>
    15 In [61]:
    16 t.x = 'x-man'
    17 #__set__ <__main__.MyDecriptor object at 0x0000025F51B03B70> <__main__.Test object at 0x0000025F51B37048> x-man
    18 In [62]:
    19 
    20 del t.x
    21 #__delete__ <__main__.MyDecriptor object at 0x0000025F51B03B70> <__main__.Test object at 0x0000025F51B37048>

    八、定制序列
    协议( Protocols)与其它编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在 Python 中的协议就显得不那么正式。事实上,在 Python 中,协议更像是一种指南。
    容器类型的协议
    1. 如果说你希望定制的容器是不可变的话,你只需要定义 __len__() 和 __getitem__() 方法。
    2. 如果你希望定制的容器是可变的话,除了 __len__() 和 __getitem__() 方法,你还需要定义 __setitem__()和 __delitem__() 两个方法。
    【例子】编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。

     1 class CountList:
     2     def __init__(self, *args):
     3         self.values = [x for x in args]
     4         self.count = {}.fromkeys( range(len(self.values)), 0)
     5     
     6     def __len__(self):
     7         return len(self.values)
     8      
     9     def __getitem__(self, item):
    10         self.count[item] += 1
    11         return self.values[item]
    12     
    13 c1 = CountList( 1, 3, 5, 7, 9)
    14 c2 = CountList( 2, 4, 6, 8, 10)
    15 print(c1[1]) #3
    16 print(c2[2])#6
    17 print(c1[ 1] + c2[ 1])#7
    18 print(c1.count) #{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
    19 print(c2.count)#{0: 0, 1: 1, 2: 3, 3: 0, 4: 0}

    1. __len__(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)。
    2. __getitem__(self, key) 定义获取容器中元素的行为,相当于 self[key] 。
    3. __setitem__(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value 。
    4. __delitem__(self, key) 定义删除容器中指定元素的行为,相当于 del self[key] 。
    【例子】编写一个可改变的自定义列表,要求记录列表中每个元素被访问的次数。

     1 class CountList:
     2     def __init__(self, *args):
     3         self.values = [x for x in args]
     4         self.count = {}.fromkeys( range(len(self.values)), 0)
     5     
     6     def __len__(self):
     7         return len(self.values)
     8     
     9     def __getitem__(self, item):
    10         self.count[item] += 1
    11         return self.values[item]
    12     
    13     def __setitem__(self, key, value):
    14         self.values[key] = value
    15         
    16 
    17     def __delitem__(self, key):
    18         del self.values[key]
    19         for i in range(0, len(self.values)):
    20             if i >= key:
    21                 self.count[i] = self.count[i + 1]
    22                 self.count.pop(len(self.values))
    23 c1 = CountList( 1, 3, 5, 7, 9)
    24 c2 = CountList( 2, 4, 6, 8, 10)
    25 print(c1[1]) #3
    26 print(c2[ 2])#6
    27 c2[2] = 12
    28 print(c1[1] + c2[2])#15
    29 print(c2.count)#{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
    30 print(c2.count)#{0: 0, 1: 0, 2: 2, 3: 0, 4: 0}

    九、迭代器
    1. 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
    2. 迭代器是一个可以记住遍历的位置的对象。
    3. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
    4. 迭代器只能往前不会后退。
    5. 字符串,列表或元组对象都可用于创建迭代器:

     1 string = 'lsgogroup'
     2 for c in string:
     3     print(c)
     4 #
     5 l
     6 s
     7 g
     8 o
     9 g
    10 r
    11 o
    12 u
    13 p
     1 for c in iter(string):
     2     print(c)
     3 
     4 '''
     5 l
     6 s
     7 g
     8 o
     9 g
    10 r
    11 o
    12 u
    13 p
    14 '''
     1 links = {'B' : ' 百度' , 'A' : ' 阿里' , 'T' : ' 腾讯' }
     2 for each in links:
     3     print('%s -> %s'  % (each, links[each]))
     4 
     5 '''
     6 B ->  百度
     7 A ->  阿里
     8 T ->  腾讯
     9 '''
    10 
    11 for each in iter(links):
    12     print('%s -> %s'  % (each, links[each]))
    13 
    14 '''
    15 B ->  百度
    16 A ->  阿里
    17 T ->  腾讯
    18 '''

    1. 迭代器有两个基本的方法: iter() 和 next() 。
    2. iter(object) 函数用来生成迭代器。
    3. next(iterator[, default]) 返回迭代器的下一个项目。
    4. iterator -- 可迭代对象
    5. default -- 可选,用于设置在没有下一个元素时返回该默认值,如果不设置,又没有下一个元素则会触发StopIteration 异常。

     1 links = {'B' : ' 百度' , 'A' : ' 阿里' , 'T' : ' 腾讯' }
     2 it = iter(links)
     3 print(next(it))#B
     4 print(next(it))#A
     5 print(next(it))#T
     6 print(next(it))#StopIteration: 
     7 
     8 it = iter(links)
     9 while True:
    10     try:
    11         each = next(it)
    12     except StopIteration:
    13         break
    14     print(each)
    15 '''
    16 B
    17 A
    18 T
    19 '''

    把一个类作为一个迭代器使用需要在类中实现两个魔法方法 __iter__() 与 __next__() 。
    1. __iter__(self) 定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了__next__() 方法并通过 StopIteration 异常标识迭代的完成。
    2. __next__() 返回下一个迭代器对象。
    3. StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

     1 class Fibs:
     2     def __init__(self, n=10):
     3         self.a = 0
     4         self.b = 1
     5         self.n = n
     6         
     7     def __iter__(self):
     8         return self
     9     
    10     def __next__(self):
    11         self.a, self.b = self.b, self.a + self.b
    12         if self.a > self.n:
    13             raise StopIteration
    14         return self.a
    15 fibs = Fibs(100)
    16 for each in fibs:
    17     print(each, end=' ' ) #1 1 2 3 5 8 13 21 34 55 89 

    十、生成器
    1. 在 Python 中,使用了 yield 的函数被称为生成器( generator)。
    2. 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
    3. 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
    4. 调用一个生成器函数,返回的是一个迭代器对象。

     1 def myGen():
     2     print(' 生成器执行! ' )
     3     yield 1
     4     yield 2
     5 myG = myGen()
     6 print(next(myG))
     7 '''
     8  生成器执行! 
     9 1
    10 '''
    11 print(next(myG)) #2
    12 print(next(myG)) # StopIteration:
    13 myG = myGen()
    14 for each in myG:
    15     print(each)
    16 '''
    17  生成器执行! 
    18 1
    19 2
    20 '''

    【例子】用生成器实现斐波那契数列。

    def libs(n):
        a = 0
        b = 1
        while True:
            a, b = b, a + b
            if a > n:
                return
            yield a
    
    for each in libs(100):
        print(each, end=' ' )
    #1 1 2 3 5 8 13 21 34 55 89 

    练习题:

    1、上面提到了许多魔法方法,如__new__,__init____str__,__rstr__,__getitem__,__setitem__等等,请总结它们各自的使用方法。

    __new__ :对象实例化时调用的第一个方法,至少需要一个参数cls,此参数代表要实例化的类。该方法对当前类进行实例化,并将当前类返回,传至 init 的 self 中。
    __init__:类实例化时自动调用
    __str__:当打印一个对象,使用%s格式化或者强制转换时候触发
    __rstr__:没有这个
    __getitem__:定义获取容器中元素的行为
    __setitem__:定义设置容器中制定元素的行为

    2、利用python做一个简单的定时器类
    要求:
    a. 定制一个计时器的类。
    b. start 和 stop 方法代表启动计时和停止计时。
    c. 假设计时器对象 t1 , print(t1) 和直接调用 t1 均显示结果。
    d. 当计时器未启动或已经停止计时时,调用 stop 方法会给予温馨的提示。
    e. 两个计时器对象可以进行相加: t1+t2 。
    f. 只能使用提供的有限资源完成。

     1 import time
     2 class TimeCount:
     3     start_time = 0
     4     stop_time = 0
     5     def __add__(self,  other):
     6         together = int.__add__(self.secs,  other.secs)
     7         return '总共运行了%d秒' % together
     8     def __repr__(self):
     9         ret = getattr(self,  'secs',  '未开始计时')
    10         if isinstance(ret,  int):
    11             return '总共运行了%d秒' % ret
    12         return ret
    13     def start(self):
    14         self.start_time = time.time()
    15         print('开始计时!')
    16     def stop(self):
    17         if self.start_time == 0:
    18             print('请先调用 start() 开始计时!')
    19         else:
    20             self.stop_time = time.time()
    21             self.secs = round(self.stop_time - self.start_time)
    22 a = TimeCount()
    23 a#未开始计时
    24 a.stop()
    25 #请先调用 start() 开始计时!
    26 a.start()#开始计时!
    27 a.stop()
    28 a
    29 #总共运行了16秒
    30 b = TimeCount()
    31 b.start()
    32 #开始计时!
    33 b.stop()
    34 b
    35 #总共运行了6秒
    36 a + b
    37 #'总共运行了22秒'

     

  • 相关阅读:
    获取设备和 App 信息
    使用 UICollectionView 实现网格化视图效果
    UIImage 读取图片内存优化
    使用 stretchableImageWithLeftCapWidth 方法实现可伸缩图片
    使用 StoryBoard 实现左右按钮切换图片的浏览效果
    二维码图片生成(扩展知识:创建带圆角效果的图片)
    Objective-C语法之扩展(Extension)的使用
    Objective-C语法之字符串NSString去掉前后空格或回车符(可以是NSCharacterSet类型的其它字符)
    Objective-C语法之可变参数
    什么时候layoutSubview会被调用
  • 原文地址:https://www.cnblogs.com/mindy-snail/p/14218561.html
Copyright © 2011-2022 走看看