strong, weak, unowned – Reference Counting in Swift

Swift: Loading Images Asynchronously and storing with NSCache and NSURLCache

my review point is 9/10

https://youtu.be/BIgqHLTZ_a4?t=1m55s   getting image from url ( NSURLSession.sharedSession().dataTaskWithURL )

https://youtu.be/BIgqHLTZ_a4?t=7m18s   개발자가 만들어 사용하는 image caching example

https://youtu.be/BIgqHLTZ_a4?t=10m45s   memory low warning hook ( didReceiveMemoryWarning )

https://youtu.be/BIgqHLTZ_a4?t=11m30s   apple에서 제공하는 NSCache를 이용한 caching 작업

https://youtu.be/BIgqHLTZ_a4?t=13m45s   url작업은 기본 cache 기능이 있는데 이 기준치를 변경하는 방법 ( NSURLCache )

Swift: Firebase 3 – How to Implement Interactive Keyboard using inputAccessoryView (Ep 15)

my review point is 9/10

https://youtu.be/ky7YRh01by8?t=2m50s   keyboard가 화면에 디스플레이될때 호출되는 hook ( NSNotificationCenter, UIKeyboardWillShowNotification )

https://youtu.be/ky7YRh01by8?t=4m25s   getting keyboard height 

https://youtu.be/ky7YRh01by8?t=5m22s   change textfield location

https://youtu.be/ky7YRh01by8?t=8m42s   add animation ( changing textfield location , animateWithDuration , layoutIfNeeded)

https://youtu.be/ky7YRh01by8?t=10m46s   remove observer of notification ( 이렇게 제거하지 않으면 memory leak의 위험이 있다, viewDidDisappear , UINotificationCenter)

https://youtu.be/ky7YRh01by8?t=13m40s   collection view에서 화면을 아래로 드래그 하는 경우 하단의 키보드도 서서히 밑으로 사라지게 하는 기능을 설정하는 경우 ( 컬렉션뷰obj.keyboardDismissMode = .Interactive )

https://youtu.be/ky7YRh01by8?t=15m14s   customizing 기본 textfield와 그에 따른 view controller의 behavior ( inputAccessoryView ,  canBecomeFirstResoponder)

https://youtu.be/ky7YRh01by8?t=23m50s   화면의 orientation을 바꾸는 경우 view.frame.width는 그 크기가 바뀌지 않는다. 그러나 UIScreen.mainScreen().bounds.width는 변한다. 

Memory Safety


Understanding Conflicting Access to Memory

// A write access to the memory where one is stored.
var one = 1
// A read access from the memory where one is stored.
print(“We’re number (one)!”)

A conflicting access to memory can occur when different parts of your code are trying to access the same location in memory at the same time. 

NOTE

If you’ve written concurrent or multithreaded code, conflicting access to memory might be a familiar problem. However, the conflicting access discussed here can happen on a single thread and doesn’t involve concurrent or multithreaded code.

If you have conflicting access to memory from within a single thread, Swift guarantees that you’ll get an error at either compile time or runtime. For multithreaded code, use Thread Sanitizer to help detect conflicting access across threads.

Characteristics of Memory Access

There are three characteristics of memory access to consider in the context of conflicting access: whether the access is a read or a write, the duration of the access, and the location in memory being accessed. Specifically, a conflict occurs if you have two accesses that meet all of the following conditions:

  • At least one is a write access.
  • They access the same location in memory.
  • Their durations overlap.

there are several ways to access memory, called long-term accesses, that span the execution of other code. The difference between instantaneous access and long-term access is that it’s possible for other code to run after a long-term access starts but before it ends, which is called overlap. A long-term access can overlap with other long-term accesses and instantaneous accesses.

Overlapping accesses appear primarily in code that uses in-out parameters in functions and methods or mutating methods of a structure. The specific kinds of Swift code that use long-term accesses are discussed in the sections below.

Conflicting Access to In-Out Parameters

A function has long-term write access to all of its in-out parameters. The write access for an in-out parameter starts after all of the non-in-out parameters have been evaluated and lasts for the entire duration of that function call. If there are multiple in-out parameters, the write accesses start in the same order as the parameters appear.

One consequence of this long-term write access is that you can’t access the original variable that was passed as in-out, even if scoping rules and access control would otherwise permit it—any access to the original creates a conflict. For example:

var stepSize = 1
func incrementInPlace(_ number: inout Int) {
   number += stepSize
}
incrementInPlace(&stepSize)
// Error: conflicting accesses to stepSize

image

One way to solve this conflict is to make an explicit copy of stepSize:

// Make an explicit copy.
var copyOfStepSize = stepSize
incrementInPlace(&copyOfStepSize)
// Update the original.
stepSize = copyOfStepSize
// stepSize is now 2

Another consequence of long-term write access to in-out parameters is that passing a single variable as the argument for multiple in-out parameters of the same function produces a conflict. For example:

func balance(_ x: inout Int, _ y: inout Int) {
   let sum = x + y
   x = sum / 2
   y = sum – x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)
// Error: Conflicting accesses to playerOneScore

NOTE

Because operators are functions, they can also have long-term accesses to their in-out parameters. For example, if balance(_:_:) was an operator function named <^>, writing playerOneScore <^> playerOneScore would result in the same conflict as balance(&playerOneScore, &playerOneScore).

Conflicting Access to self in Methods

참고) 기본적으로 structure,enumeration의 property는 같은 structure,enumeration내의 method를 통해 수정가능하지 않지만 mutating을 이용가능하게 할수 있다.

A mutating method on a structure has write access to self for the duration of the method call. For example, consider a game where each player has a health amount, which decreases when taking damage, and an energy amount, which decreases when using special abilities.

struct Player {
   var name: String
   var health: Int
   var energy: Int
   
   static let maxHealth = 10
   mutating func restoreHealth() {
       health = Player.maxHealth
   }
}

In the restoreHealth() method above, a write access to self starts at the beginning of the method and lasts until the method returns. In this case, there’s no other code inside restoreHealth() that could have an overlapping access to the properties of a Player instance. The shareHealth(with:) method below takes another Player instance as an in-out parameter, creating the possibility of overlapping accesses.

extension Player {
   mutating func shareHealth(with teammate: inout Player) {
       balance(&teammate.health, &health)
   }
}
var oscar = Player(name: “Oscar”, health: 10, energy: 10)
var maria = Player(name: “Maria”, health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK

In the example above, calling the shareHealth(with:) method for Oscar’s player to share health with Maria’s player doesn’t cause a conflict. There’s a write access to oscar during the method call because oscar is the value of self in a mutating method, and there’s a write access to maria for the same duration because mariawas passed as an in-out parameter. As shown in the figure below, they access different locations in memory. Even though the two write accesses overlap in time, they don’t conflict.

image

However, if you pass oscar as the argument to shareHealth(with:), there’s a conflict:

oscar.shareHealth(with: &oscar)
// Error: conflicting accesses to oscar

The mutating method needs write access to self for the duration of the method, and the in-out parameter needs write access to teammate for the same duration. Within the method, both self and teammate refer to the same location in memory—as shown in the figure below. The two write accesses refer to the same memory and they overlap, producing a conflict.

image

Conflicting Access to Properties

Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value.(structure,tuple,enurmeration의 하나의 부분에 접근하는 경우라도 전체에대한 read,write access가 필요하다.) For example, overlapping write accesses to the elements of a tuple produces a conflict:

var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// Error: conflicting access to properties of playerInformation

In the example above, calling balance(_:_:) on the elements of a tuple produces a conflict because there are overlapping write accesses to playerInformation. Both playerInformation.health and playerInformation.energy are passed as in-out parameters, which means balance(_:_:) needs write access to them for the duration of the function call. In both cases, a write access to the tuple element requires a write access to the entire tuple. This means there are two write accesses to playerInformation with durations that overlap, causing a conflict.

The code below shows that the same error appears for overlapping write accesses to the properties of a structure that’s stored in a global variable.

var holly = Player(name: “Holly”, health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // Error

In practice, most access to the properties of a structure can overlap safely. For example, if the variable holly in the example above is changed to a local variable instead of a global variable, the compiler can prove that overlapping access to stored properties of the structure is safe:

// 함수안에서 정해진 변수이면 이런경우는 각요소에 각자 접근 가능

func someFunction() {
   var oscar = Player(name: “Oscar”, health: 10, energy: 10)
   balance(&oscar.health, &oscar.energy)  // OK
}

In the example above, Oscar’s health and energy are passed as the two in-out parameters to balance(_:_:). The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.

The restriction against overlapping access to properties of a structure isn’t always necessary to preserve memory safety. Memory safety is the desired guarantee, but exclusive access is a stricter requirement than memory safety—which means some code preserves memory safety, even though it violates exclusive access to memory. Swift allows this memory-safe code if the compiler can prove that the nonexclusive access to memory is still safe. Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:

  • You’re accessing only stored properties of an instance, not computed properties or class properties.
  • The structure is the value of a local variable, not a global variable.
  • The structure is either not captured by any closures, or it’s captured only by nonescaping closures.

If the compiler can’t prove the access is safe, it doesn’t allow the access.

android finish() method doesn’t clear app from memory

original source: https://android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570

  1. Leak activity to a static reference
  2. Leak activity to a worker thread
  3. Leak thread itself

크게는 세가지 부류로 구분된다.

첫번째 부류에서 세분화된 예들

  1. Leak Activity to a static view (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/viastaticreference/LeakActivityToStaticViewActivity.java)
  2. Leak Activity to a static variable (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/viastaticreference/LeakActivityToStaticVariableActivity.java)
  3. Leak Activity to a singleton object (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/viastaticreference/LeakActivityToSingletonActivity.java)
  4. Leak Activity to a static instance of a inner class of the activity (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/viastaticreference/LeakActivityToStaticInnerClassActivity.java)

스태틱으로 지정하는 경우  그안의 내용이 app이 끝날때 까지 유지되므로 주의해야 한다. 

1 번 예제 코드 (static으로 view를 참조하는 변수를 만든 경우)

public class LeakActivityToStaticViewActivity extends AppCompatActivity {

    // FIXME: 2/26/17 static view will leak the activity. To fix it, make it non-static
    static TextView label;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        label = new TextView(this);
        label.setText(getString(R.string.leak_explanation_static_view, getString(R.string.instruction_check_for_leaks)));

        setContentView(label);
    }
}

2번 예제 코드  (static으로 activity를 참조하는 변수를 만든 경우)

public class LeakActivityToStaticVariableActivity extends AppCompatActivity {
    // FIXME: 2/26/17 static reference to the activity will leak the activity.
    // To fix it, set it null onDestroy or use weak reference
    static Activity activity = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak_context_to_static_variable);
        TextView textView = (TextView) findViewById(R.id.textView);

        if (activity == null) {
            activity = this;
        }
    }
}

3번 예제 코드  (singleton obj를 참조하는 변수를 만든 경우)

public class LeakActivityToSingletonActivity extends AppCompatActivity {

    SomeSingletonManager someSingletonManager = null;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak_context_to_singleton);
        // FIXME: fix option 1: instead of passing `this` to getInstance(), pass getApplicationContext()
        someSingletonManager = SomeSingletonManager.getInstance(this);
    }

4번 예제 코드  (static으로 inner class obj를 참조하는 변수를 만든 경우)

public class LeakActivityToStaticInnerClassActivity extends AppCompatActivity {

    private static SomeInnerClass someInnerClass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak_static_reference_to_inner_class);

        if (someInnerClass == null) {
            someInnerClass = new SomeInnerClass();
        }
    }

두번째부류에서 세분화된 예들

  1. Leak Activity to a thread (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/vialongrunningtask/LeakActivityToThreadActivity.java)
  2. Leak Activity to a handler (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/vialongrunningtask/LeakActivityToHandlerActivity.java)
  3. Leak Activity to an AsyncTask (https://github.com/frank-tan/SinsOfMemoryLeaks/blob/LEAK/app/src/main/java/com/franktan/memoryleakexamples/vialongrunningtask/LeakActivityToAsyncTaskActivity.java)

두번째 세번째 분류의 내용을 종합해 보면 activity내에서 발생된 thread의 작업이 activity lifecycle보다 길수있다. activity가 종료된 후에도 작업중인 thread에 의해 memory leak이 발생할수 있다. 그러므로 activity onDestroy()에서 thread를 적당히 처리해야 한다.